C - 序列化技术

ryy*_*yst 31 c serialization

我正在编写一些代码来序列化一些数据以通过网络发送它.目前,我使用这个原始程序:

  1. 创建一个void*缓冲区
  2. hton在我想通过网络发送的数据上应用任何字节排序操作,例如系列
  3. 用于memcpy将内存复制到缓冲区中
  4. 通过网络发送内存

问题是,对于各种数据结构(通常包含void*数据,因此您不知道是否需要关心字节排序),代码变得非常臃肿,序列化代码非常特定于每个数据结构,并且不能完全重复使用.

什么是C的一些好的序列化技术,使这更容易/更少丑陋?

-

注意:我已经绑定了一个特定的协议,所以我无法自由选择如何序列化我的数据.

jst*_*ley 35

对于每个数据结构,都有一个serialize_X函数(其中X是结构名称),它接受指向X的指针和指向不透明缓冲区结构的指针,并调用相应的序列化函数.您应该提供一些原语,例如serialize_int,它们写入缓冲区并更新输出索引.原语必须调用诸如reserve_space(N)之类的东西,其中N是在写入任何数据之前所需的字节数.reserve_space()将重新分配void*缓冲区,使其至少与当前大小加上N个字节一样大.为了实现这一点,缓冲区结构将需要包含指向实际数据的指针,将下一个字节写入的索引(输出索引)以及为数据分配的大小.使用此系统,所有serialize_X函数都应该非常简单,例如:

struct X {
    int n, m;
    char *string;
}

void serialize_X(struct X *x, struct Buffer *output) {
    serialize_int(x->n, output);
    serialize_int(x->m, output);
    serialize_string(x->string, output);
}
Run Code Online (Sandbox Code Playgroud)

框架代码将类似于:

#define INITIAL_SIZE 32

struct Buffer {
    void *data;
    int next;
    size_t size;
}

struct Buffer *new_buffer() {
    struct Buffer *b = malloc(sizeof(Buffer));

    b->data = malloc(INITIAL_SIZE);
    b->size = INITIAL_SIZE;
    b->next = 0;

    return b;
}

void reserve_space(Buffer *b, size_t bytes) {
    if((b->next + bytes) > b->size) {
        /* double size to enforce O(lg N) reallocs */
        b->data = realloc(b->data, b->size * 2);
        b->size *= 2;
    }
}
Run Code Online (Sandbox Code Playgroud)

从这里,实现所需的所有serialize_()函数应该非常简单.

编辑:例如:

void serialize_int(int x, Buffer *b) {
    /* assume int == long; how can this be done better? */
    x = htonl(x);

    reserve_space(b, sizeof(int));

    memcpy(((char *)b->data) + b->next, &x, sizeof(int));
    b->next += sizeof(int);
}
Run Code Online (Sandbox Code Playgroud)

编辑:还要注意我的代码有一些潜在的错误.缓冲区数组的大小存储在size_t中,但索引是一个int(我不确定size_t是否被认为是索引的合理类型).此外,没有提供错误处理,也没有在完成后释放缓冲区的功能,因此您必须自己完成此操作.我只是演示了我将使用的基本架构.

  • 在文件前加上一些魔术字节和版本号也是一个好主意,以便快速区分您绝对无法处理的传入数据.还可以为每个结构提供版本.最后但并非最不重要的一点:在"从外部"解析数据时要偏执,不小心会让你的程序受到攻击,或至少不稳定. (3认同)

Ass*_*vie 6

我会说绝对不要尝试自己实现序列化。它已经完成了无数次,您应该使用现有的解决方案。例如 protobufs:https : //github.com/protobuf-c/protobuf-c

它还具有与许多其他编程语言兼容的优点。


Ber*_*mos 5

我建议使用图书馆。

由于对现有的数据库不满意,我创建了Binn库以使我们的生活更轻松。

这是使用它的一个例子:

  binn *obj;

  // create a new object
  obj = binn_object();

  // add values to it
  binn_object_set_int32(obj, "id", 123);
  binn_object_set_str(obj, "name", "Samsung Galaxy Charger");
  binn_object_set_double(obj, "price", 12.50);
  binn_object_set_blob(obj, "picture", picptr, piclen);

  // send over the network
  send(sock, binn_ptr(obj), binn_size(obj));

  // release the buffer
  binn_free(obj);
Run Code Online (Sandbox Code Playgroud)