最简单的方法可能是分配一块内存来保存所有内容。例如,考虑如下结构:
typedef struct A {
int v;
char* str;
} our_struct_t;
现在,最简单的方法是创建一个定义的格式并将其打包到一个字节数组中。我将尝试展示一个示例:
int sLen = 0;
int tLen = 0;
char* serialized = 0;
char* metadata = 0;
char* xval = 0;
char* xstr = 0;
our_struct_t x;
x.v = 10;
x.str = "Our String";
sLen = strlen(x.str); // Assuming null-terminated (which ours is)
tLen = sizeof(int) + sLen; // Our struct has an int and a string - we want the whole string not a mem addr
serialized = malloc(sizeof(char) * (tLen + sizeof(int)); // We have an additional sizeof(int) for metadata - this will hold our string length
metadata = serialized;
xval = serialized + sizeof(int);
xstr = xval + sizeof(int);
*((int*)metadata) = sLen; // Pack our metadata
*((int*)xval) = x.v; // Our "v" value (1 int)
strncpy(xstr, x.str, sLen); // A full copy of our string
所以这个例子将数据复制到一个大小数组中,2 * sizeof(int) + sLen
它允许我们使用单个整数元数据(即字符串长度)和从结构中提取的值。要反序列化,您可以想象如下:
char* serialized = // Assume we have this
char* metadata = serialized;
char* yval = metadata + sizeof(int);
char* ystr = yval + sizeof(int);
our_struct_t y;
int sLen = *((int*)metadata);
y.v = *((int*)yval);
y.str = malloc((sLen + 1) * sizeof(char)); // +1 to null-terminate
strncpy(y.str, ystr, sLen);
y.str[sLen] = '\0';
如您所见,我们的字节数组是明确定义的。下面我详细介绍了结构:
- 字节 0-3:元数据(字符串长度)
- 字节 4-7:Xv(值)
- 字节 8 - sLen:X.str(值)
如果您遵循定义的约定,这种定义明确的结构允许您在任何环境中重新创建结构。现在,要通过套接字发送此结构取决于您如何开发协议。您可以首先发送一个包含您刚刚构建的数据包总长度的整数数据包,或者您可以期望首先/单独发送元数据(逻辑上分开,这在技术上仍然可以同时发送)然后你知道在客户端接收多少数据。例如,如果我收到元数据值10
then 我可以期望sizeof(int) + 10
字节跟随完成结构。一般来说,这可能是14
字节。
编辑
我将根据评论中的要求列出一些澄清。
我做了一个完整的字符串副本,所以它在(逻辑上)连续的内存中。也就是说,我的序列化数据包中的所有数据实际上都是完整数据——没有指针。这样,我们可以serialized
通过套接字发送单个缓冲区(我们称之为 is )。如果只是发送指针,接收指针的用户会期望该指针是有效的内存地址。但是,您的内存地址不太可能完全相同。但是,即使是这样,他在该地址的数据也不会与您相同(除非在非常有限和特殊的情况下)。
希望通过查看反序列化过程(这是在接收方方面)可以更清楚地说明这一点。请注意我如何分配一个结构来保存发件人发送的信息。如果发送者没有向我发送完整的字符串,而只是发送了内存地址,我实际上无法重建发送的数据(即使在同一台机器上,我们有两个不同的虚拟内存空间也不相同)。所以本质上,指针只是对发起者的一个很好的映射。
最后,就“结构中的结构”而言,每个结构都需要多个函数。也就是说,您可以重用这些功能。例如,如果我有两个结构A
和B
where A
contains B
,我可以有两个序列化方法:
char* serializeB()
{
// ... Do serialization
}
char* serializeA()
{
char* B = serializeB();
// ... Either add on to serialized version of B or do some other modifications to combine the structures
}
所以你应该能够为每个结构使用一个序列化方法。