序列化与反序列化
核心概念:序列化与反序列化
想象一下,想把一个乐高模型(代码中的结构化数据)通过快递寄给朋友。
-
序列化 (Serialization / Marshal):就像是把乐高模型拆散,按照特定的顺序和规则,一块一块地放进盒子里,并附上一张说明书(协议),说明每块积木应该放在哪个位置。这个过程将一个结构化的、易于操作的对象(乐高模型)转换成了一个扁平的、用于存储或传输的字节序列(盒子里的积木堆)。
- 目的:为了存储(比如保存到文件)或网络传输(比如通过网络发送)。
- 关键词:对象/结构体 -> 字节流
-
反序列化 (Deserialization / UnMarshal):就是你的朋友收到快递后,根据同一份说明书,把盒子里的积木重新拼回原来的乐高模型。这个过程是序列化的逆过程,它将接收到的字节序列根据约定的协议,重新构建成内存中一个可操作的、结构化的对象。
- 目的:从存储介质或网络接收端重建可操作的对象。
- 关键词:字节流 -> 对象/结构体
在代码中,Marshal 和 UnMarshal 是这两个过程的另一种叫法,尤其在Windows编程和历史悠久的库中很常见。
结合代码理解
把代码拆解到上面的比喻中:
// 步骤6:UDS消息反序列化(将二进制字节数组转换为可操作的UDS消息对象)
auto uds_msg = UDSMessage(std::move(uds_data_vec)); // 1. 拿到“快递盒子”
auto parse_res = uds_msg.UnMarshal(); // 2. 开始“拼装乐高”
-
UDSMessage(std::move(uds_data_vec))uds_data_vec是一个vector<uint8_t>,即一个字节数组(uint8_t通常代表一个字节)。这就像是那盒刚从网络或文件里读取出来的、杂乱但有序的积木块(二进制数据)。- 这行代码创建了一个空的
UDSMessage对象uds_msg(一个还没拼的乐高模型框架),并将装满二进制数据的“盒子”移交(move)给了它。现在,uds_msg持有了原始数据。
-
uds_msg.UnMarshal()- 这是最关键的步骤。
UnMarshal()方法是UDSMessage类的成员函数,它的职责就是充当那份“说明书”。 - 它内部会按照 UDS协议(ISO 14229标准) 的规定,来解析它持有的字节数组 (
uds_data_vec)。 - 具体“拼装”过程可能包括:
- 读取第一个字节,解析出服务ID(SID)。比如
0x2E代表WriteDataByIdentifier服务,0x10代表DiagnosticSessionControl服务。 - 根据不同的服务ID,继续解析后续的字节。
- 例如,对于
WriteDataByIdentifier服务,它知道接下来的2个字节是数据标识符(DID),再后面的字节是要写入的数据。 - 它会把这些解析出来的值,分别赋值给
UDSMessage对象的成员变量,比如:m_sid(服务ID)m_did(数据标识符)m_payload(数据负载)m_sub_function(子功能,如果该服务有的话)
- 读取第一个字节,解析出服务ID(SID)。比如
parse_res可能是一个布尔值或枚举值,用来指示反序列化是否成功。如果数据不符合协议规范(比如长度不对、SID未知),UnMarshal()就会失败。
- 这是最关键的步骤。
总结:如何理解“二进制流 → 结构化对象”
| 步骤 | 比喻 | 你的代码 | 数据形态 |
|---|---|---|---|
| 序列化 (Marshal) | 把乐高模型拆解放入盒子 | UDSMessage.Marshal() |
结构化对象 → 二进制字节流 |
| 传输/存储 | 寄送快递盒子 | 通过CAN/LIN/DoIP等网络传输 | 二进制字节流 |
| 反序列化 (UnMarshal) | 根据说明书拼回模型 | uds_msg.UnMarshal() |
二进制字节流 → 结构化对象 |
所以,uds_msg.UnMarshal() 执行成功后,uds_msg 就不再是一盒杂乱无章的积木了,而是一个拼装好的、你可以轻松查询和操作的对象。
可以像这样使用它(假设类提供了相应的接口):
if(parse_res == true) {
std::cout << "Received UDS request for service: 0x" << std::hex << uds_msg.GetServiceId() << std::endl;
if(uds_msg.GetServiceId() == 0x2E) {
std::cout << "It wants to write to DID: 0x" << uds_msg.GetDid() << std::endl;
// 然后你可以处理这个写入请求...
}
}
这就是反序列化的巨大意义——它让程序能够理解并方便地处理原始的二进制网络数据。
浙公网安备 33010602011771号