序列化与反序列化

核心概念:序列化与反序列化

想象一下,想把一个乐高模型(代码中的结构化数据)通过快递寄给朋友。

  • 序列化 (Serialization / Marshal):就像是把乐高模型拆散,按照特定的顺序和规则,一块一块地放进盒子里,并附上一张说明书(协议),说明每块积木应该放在哪个位置。这个过程将一个结构化的、易于操作的对象(乐高模型)转换成了一个扁平的、用于存储或传输的字节序列(盒子里的积木堆)。

    • 目的:为了存储(比如保存到文件)或网络传输(比如通过网络发送)。
    • 关键词:对象/结构体 -> 字节流
  • 反序列化 (Deserialization / UnMarshal):就是你的朋友收到快递后,根据同一份说明书,把盒子里的积木重新拼回原来的乐高模型。这个过程是序列化的逆过程,它将接收到的字节序列根据约定的协议,重新构建成内存中一个可操作的、结构化的对象

    • 目的:从存储介质或网络接收端重建可操作的对象
    • 关键词:字节流 -> 对象/结构体

在代码中,MarshalUnMarshal 是这两个过程的另一种叫法,尤其在Windows编程和历史悠久的库中很常见。


结合代码理解

把代码拆解到上面的比喻中:

// 步骤6:UDS消息反序列化(将二进制字节数组转换为可操作的UDS消息对象)
auto uds_msg = UDSMessage(std::move(uds_data_vec)); // 1. 拿到“快递盒子”
auto parse_res = uds_msg.UnMarshal();               // 2. 开始“拼装乐高”
  1. UDSMessage(std::move(uds_data_vec))

    • uds_data_vec 是一个 vector<uint8_t>,即一个字节数组(uint8_t 通常代表一个字节)。这就像是那盒刚从网络或文件里读取出来的、杂乱但有序的积木块(二进制数据)
    • 这行代码创建了一个空的 UDSMessage 对象 uds_msg(一个还没拼的乐高模型框架),并将装满二进制数据的“盒子”移交(move)给了它。现在,uds_msg 持有了原始数据。
  2. 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 (子功能,如果该服务有的话)
    • 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;
    // 然后你可以处理这个写入请求...
  }
}

这就是反序列化的巨大意义——它让程序能够理解并方便地处理原始的二进制网络数据。

posted on 2026-02-05 10:24  四季萌芽V  阅读(4)  评论(0)    收藏  举报

导航