在C中序列化一个简单的结构

时间:2013-10-30 13:39:15

标签: c serialization

我正在最终确定客户端/服务器程序,其中客户端使用堆栈执行二进制代码。客户端必须能够连接到服务器,然后服务器将继续执行堆栈。为此,我需要将我的堆栈结构发送到服务器。所以我需要首先序列化我的“堆栈”对象,然后反序列化它,但我不擅长那个关闭指针操作。我一直在寻找一个lib,但谷歌的JSON和Prot-c看起来很复杂,所以如果我能得到一些帮助来手动序列化/反序列化那个堆栈,那将非常方便。

我的堆栈基于列表实现:

struct list {
  int Element;
  list next;
};

struct stack 
{
  list l;
};

将现有的“堆栈”对象发送到服务器的最简单方法是什么?

感谢名单!

5 个答案:

答案 0 :(得分:1)

基于图书馆:

BSON代替JSON,它比Google协议缓冲区轻,但仍然有点笨重。

可以找到更便宜的替代品here

自己实施:

next字段的类型应为list*而不是list。否则你有一个循环定义,一个列表不能合理地包含整个其他列表。

另外,就个人品味而言,我会将内部列表节点数据类型node和列表提示(第一个节点)称为list

此外,您需要typedef struct list list才能在其他结构定义中使用listlist*

示例:

/* 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;
}

答案 1 :(得分:0)

指定的列表结构是递归定义的。我想你的意思是

typedef struct list list;

struct list {
 int element;
 list *next
}

在这种情况下,它是一个简单的一维列表。您可以简单地将其展平为int element数组,并将其重新构建为列表服务器端。

答案 2 :(得分:0)

如果您不需要任何流量优化,您可以将结构使用的内存视为字节数组(它可能非常特定于平台,所以要小心,特别是在客户端和服务器上使用不同的32位和64位体系结构时)。并将其作为简单的字符串发送。

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;
}     

另外,为了避免使用指向下一个结构的指针的某些分段错误,最好添加下一个结构的一些id并使用它进行存储和操作。

struct list{
    int element;
    int list_id;
}

答案 3 :(得分:0)

如果您知道列表的大小,可以分配一个包含列表大小的数组,然后用列表填充数组。

答案 4 :(得分:0)

假设存在push,如下所示,您可以使用recv_stacksend_stack功能,如下所示。错误报告很简陋,但结构很容易改进。

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;
}