我正在编写一些代码来序列化一些数据以通过网络发送它.目前,我使用这个原始程序:
void*
缓冲区hton
在我想通过网络发送的数据上应用任何字节排序操作,例如系列memcpy
将内存复制到缓冲区中问题是,对于各种数据结构(通常包含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是否被认为是索引的合理类型).此外,没有提供错误处理,也没有在完成后释放缓冲区的功能,因此您必须自己完成此操作.我只是演示了我将使用的基本架构.
我会说绝对不要尝试自己实现序列化。它已经完成了无数次,您应该使用现有的解决方案。例如 protobufs:https : //github.com/protobuf-c/protobuf-c
它还具有与许多其他编程语言兼容的优点。
我建议使用图书馆。
由于对现有的数据库不满意,我创建了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)