【问题标题】:Serialization issues while sending struct over socket通过套接字发送结构时的序列化问题
【发布时间】:2013-09-02 03:21:51
【问题描述】:

我正在开发基于 UDP 的客户端/服务器,我想从服务器向客户端发送不同的消息。为每条消息定义了不同的 C 结构。

我想了解我序列化数据的方式出了什么问题。

struct Task
{
    int mType;
    int tType;
    int cCnt;
    int* cId;
    char data[128];
};

序列化/反序列化函数

unsigned char * serialize_int(unsigned char *buffer, int value)
{
    buffer[0] = value >> 24;
    buffer[1] = value >> 16;
    buffer[2] = value >> 8;
    buffer[3] = value;
    return buffer + 4;
}

unsigned char * serialize_char(unsigned char *buffer, char value)
{
    buffer[0] = value;
    return buffer + 1;
}

int deserialize_int(unsigned char *buffer)
{
    int value = 0;

    value |= buffer[0] << 24;
    value |= buffer[1] << 16;
    value |= buffer[2] << 8;
    value |= buffer[3];
    return value;

}

char deserialize_char(unsigned char *buffer)
{
    return buffer[0];
}

序列化结构的发送方代码

unsigned char* serializeTask(unsigned char* msg, const Task* t)
{
    msg = serialize_int(msg,t->mType);
    msg = serialize_int(msg,t->tkType);
    msg = serialize_int(msg,t->cCnt);
    for(int i=0; i<t->cCnt; i++)
            msg = serialize_int(msg,t->cId[i*4]);

for(int i=0; i<strlen(data); i++)
    msg = serialize_char(msg,t->data[i]);

    return msg;
}

用于反序列化数据的接收端代码

printf("Msg type:%d\n", deserialize_int(message) );
printf("Task Type:%d\n", deserialize_int(message+4) );
printf("Task Count:%d\n", deserialize_int(message+8));

Output 
Msg type:50364598         //Expected value is 3
Task Type:-2013036362     //Expected value is 1
Task Count:1745191094     //Expected value is 3  

问题 1:
为什么反序列化的值与预期的不一样?

问题 2:
序列化/反序列化方法与 memcpy 有何不同?

Task t;
memcpy(&t, msg, sizeof(t));  //msg is unsigned char* holding the struct data  

编辑

调用serializeTask的代码

void addToDatabase(unsigned char* message, int msgSize, Task* task)
{
    message = new unsigned char[2*msgSize+1];
    unsigned char* msg = message;  //To preserve start address of message
    message = serializeTask(message, task); //Now message points to end of the array

//Insert serialized data to DB
//msg is inserted to DB 
}

存储在DB中的序列化数据

Message:
00 
03 70 B6 88 03 70 B6 68 05 70 B6 68 05 70 B6 00 
00 00 00 00 00 00 00 A8 05 70 B6 AC 05 70 B6 B4 
05 70 B6 C9 05 70 B6 DE 05 70 B6 E6 05 70 B6 EE 
05 70 B6 FB 05 70 B6 64 65 66 00 63 6F 68 6F 72 
74 73 00 70 65 6E 64 69 6E 67 5F 61 73 73 69 67 
6E 5F 74 61 73 6B 73 00 70 65 6E 64 69 6E 67 5F 
61 73 73 69 67 6E 5F 74 61 73 6B 73 00 6D 65 73 
73 61 67 65 00 6D 65 73 73 61 67 65 00 3F 00 FF 
FF 00 00 FC 90 00 00 00 00 00 00 00 C9 2D B7 00 
00 00 00 10 06 70 B6 00 00 00 00 00 00 00 00 30 
06 70 B6 34 06 70 B6 3C 06 70 B6

【问题讨论】:

  • 能否展示调用serializeTask的代码?
  • 在发送前和接收后检查调试器中的缓冲区。
  • 在发送者和接收者上以十六进制对的形式输出消息可能是个好主意,以确保它正确通过,然后再转向序列化函数。
  • @paddy 在服务器端本身,我将序列化的数据存储到数据库中并尝试检索它并反序列化。还是数据不一样。我将发布十六进制数据。
  • @KyleLemons 添加了代码..

标签: c serialization struct deserialization


【解决方案1】:

OP在serializeTask()有2个问题

for(int i=0; i<t->cCnt; i++)
  msg = serialize_int(msg,t->cId[i*4]); [i*4]
...
for(int i=0; i<strlen(data); i++)
  msg = serialize_char(msg,t->data[i]); strlen(data)

应该是(假设 i&lt;strlen(data) 应该是 i&lt;strlen(t-&gt;data)

for(int i=0; i<t->cCnt; i++)
  msg = serialize_int(msg,t->cId[i]);  // [i]
...
for(int i=0; i<strlen(t->data); i++)   // strlen(data) + 1
  msg = serialize_char(msg,t->data[i]);

第一个 for 循环每 4 个cId[] 序列化一次。 OP 当然想序列化连续的cId[]
仅序列化了 data 字符串的长度。 OP 当然想序列化所有 NUL 终止字节。


发布缓冲区中的数据更可能是下面的,这与序列化代码匹配。这意味着填充Task* t 的更高级别代码是错误的。我确信在字段mTypetkType 中看到的值要么是指针要么是float,同样Task* t 在序列化之前很可能有问题。

0xb6700300 or -3.576453e-06
0xb6700388 or -3.576484e-06
0xb6700568 or -3.576593e-06
0xb6700568 or -3.576593e-06
0x000000 or 0.000000e+00
0x000000 or 0.000000e+00
0xb67005a8 or -3.576608e-06
0xb67005ac or -3.576609e-06
0xb67005b4 or -3.576611e-06
0xb67005c9 or -3.576615e-06
0xb67005de or -3.576620e-06
0xb67005e6 or -3.576622e-06
0xb67005ee or -3.576624e-06
0xb67005fb or -3.576627e-06
def\0cohorts\0pending_assign_tasks\0pending_assign_tasks\0message\0message\0?\0
...

【讨论】:

    猜你喜欢
    • 2016-04-04
    • 2011-06-18
    • 2010-11-22
    • 2016-06-06
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    相关资源
    最近更新 更多