2

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

我的堆栈基于列表实现:

struct list {
  int Element;
  list next;
};

struct stack 
{
  list l;
};

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

谢谢!

4

5 回答 5

1

基于库:

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

可以在这里找到更便宜的替代品。

自己的实现:

next字段的类型应为list*not 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;
}
于 2013-10-30T13:51:42.730 回答
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;
}
于 2013-10-30T14:07:34.873 回答
0

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

于 2013-10-30T14:07:40.993 回答
0

假设存在push如下,你可以使用如下的recv_stackandsend_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;
}
于 2014-09-11T19:45:38.050 回答
0

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

typedef struct list list;

struct list {
 int element;
 list *next
}

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

于 2013-10-30T13:50:41.023 回答