Reputation: 65
i am finalizing a client/server program where the client is executing binary code by using a stack. The client must me able to connect to a server who will then continue the stack execution. To do this, i need to send my stack structure to the server. So i need to serialize my "stack" object first and then deserialize it but i'm not good at that close pointer manipulation. I've been looking for a lib, but JSON and Prot-c from google seem heavy and complicated, so if i could get some help to manually serialize/deserialize that stack it would be really handy.
My stack is based on a list implementation:
struct list {
int Element;
list next;
};
struct stack
{
list l;
};
What's the easyiest way for me to send an existing "stack" object to my server ?
Thanx!
Upvotes: 2
Views: 273
Reputation: 215
Assuming the existence of push
as below, you can use the recv_stack
and send_stack
function as below. Error report is rudimentary but it is structured so that it is easy to improve on it.
void push(int k, struct stack* s);
#define ERR_SUCCESS 0
#define ERR_PROTOCOL 1
void send_int(FILE* f, int k)
{
fprintf(f, "%d", k);
}
void send_stack(FILE* f, const struct stack* s)
{
int flag = 0;
const struct list* a = &s->l;
fprintf(f, "{ ");
while(a != NULL)
{
send_int(f, a->Element);
a = a->next;
if(flag)
{
fprintf(f, ", ");
}
flag = 1;
}
fprintf(f, " }\n");
}
#define RECV_READ_LBRACE 1
#define RECV_READ_INTEGER 2
#define RECV_CONT_INTEGER 3
#define RECV_FINAL 4
int
recv_stack(FILE* f, struct stack* s)
{
int state = RECV_READ_LBRACE;
int error = ERR_SUCCESS;
int ax = 0;
do {
char c = fgetc(f);
switch(state)
{
case RECV_READ_LBRACE:
if(c == '{')
{
state = RECV_READ_INTEGER;
}
else
{
state = RECV_FINAL;
error = ERR_PROTOCOL;
}
break;
case RECV_READ_INTEGER:
if(isdigit(c))
{
state = RECV_CONT_INTEGER;
ax = c - '0';
}
else if(c != ' ')
{
state = RECV_FINAL;
error = ERR_PROTOCOL;
}
break;
case RECV_CONT_INTEGER:
if(isdigit(c))
{
ax *= 10;
ax += c - '0';
}
else if(c == ',')
{
state = RECV_READ_INTEGER;
push(ax, s);
}
else if(c == '}')
{
state = RECV_FINAL;
push(ax, s);
}
else
{
state = RECV_FINAL;
error = ERR_PROTOCOL;
}
break;
}
} while(state != RECV_FINAL);
return error;
}
Upvotes: 0
Reputation: 71
Your list struct as specified is recursively defined. I suppose you meant
typedef struct list list;
struct list {
int element;
list *next
}
In which case it is a simple one-dimensional list. You could simply flatten it to an array of int element
and reconstruct it as a list server-side.
Upvotes: 0
Reputation: 901
If you know your list's size, you can alloc an array with the size of your list and then fill the array with your list.
Upvotes: 0
Reputation: 499
If you don't need any traffic optimisation, you can treat memory used by your struct as array of bytes (it can be very platform specific, so be carefull, specially when using different 32 and 64 bit architectures at client and server). And send it as simple string.
struct to_send{
struct stack _stack;
struct list _list;
};
int send(struct to_send data){
char *string;
string = (char*)malloc(sizeof(struct to_send));
memcpy(string, &data, sizeof(struct to_send));
/* some abstract function which transfers string to client - tx(char *data, int len)*/
tx(string, sizeof(struct to_send));
return 1;
}
/* function that receives string and converts it back to structure */
struct to_send *recv(char *input, int len){
struct to_send *data;
data = (struct to_send*)malloc(sizeof(struct to_send));
memcpy(data, input, len);
return data;
}
Also to avoid some segmentation faults with pointer to next structure, better to add some id of next structure and store and manipulate with it.
struct list{
int element;
int list_id;
}
Upvotes: 0
Reputation: 16107
BSON in stead of JSON, it's lighter than Google Protocol buffers but still it's a bit bulky.
Cheaper alternatives can be found here.
The next
field should be of type list*
not list
. Otherwise you have a cyclic definition, a list can't reasonably contain an entire other list.
Also as a matter of personal taste, I'd call the internal list node datatype node
and the tip of list (the first node) I'd alias as list
.
Also you'd need to typedef struct list list
in order to use list
or list*
in other struct definitions.
Example:
/* this is your list.h file */
/* Forward declaration of `node` allows us to use
* `node` as a datatype in stead of using `struct node`
* everywhere.
*/
typedef struct node node;
/* Creating an alias called `list` for `node` types
* we will only use this when refferring to the first
* node of the list.
*/
typedef node list;
/* A container that will help us carry around multiple
* types of data.
*/
typedef struct any_value any_value;
/* An enum that will be used by the any_value container
* to discern what type of data is currently present.
*/
typedef enum type_flag type_flag;
/* this is your list.c file */
struct node {
/* A void pointer to the value allows us to use
* different types of values.
*/
any_value value;
node* next;
node* prev;
}
enum type_flag {
INTEGER, STRING, SUBLIST
}
struct any_value {
type_flag type;
int length;
void* value;
}
Upvotes: 1