2

我需要通过串行端口传输数据。为了确保数据的完整性,我想要一个围绕每个 protobuf 消息的小信封协议。我想到了以下几点:

  1. 消息类型(1 字节)
  2. 消息大小(2 个字节)
  3. protobuf 消息(N 字节)
  4. (校验和;可选)

消息类型主要是 proto 文件中定义的消息之间的映射。但是,如果消息损坏或某些字节丢失,则消息大小将不正确,并且无法再解释所有后续字节。解决这个问题的一种方法是在消息之间引入限制器,但为此我需要选择 protobuf 不使用的东西。是否存在任何 protobuf 消息从未使用过的字节序列?

我也想过另一种方式。如果 master 发现包损坏,它应该将通信重置为干净的开始。为此,我希望主机向从机发送 RESTART 命令。从机应以 ACK 应答,然后再次开始发送完整消息。在 RESTART 和 ACK 之间接收到的所有字节都将被主机丢弃。我想将 ACK 和 RESTART 编码为特殊消息。但是使用这种方法我面临同样的问题:我需要为 ACK 和 RESTART 找到未被任何 protobuf 消息使用的字节序列。

也许我也采取了错误的方法 - 随意建议其他方法来处理丢失的字节。

4

2 回答 2

1

在出现罕见问题后帮助恢复数据包同步的一种方法是在消息的开头使用同步字,并使用校验和来检查有效消息。

这意味着您在消息类型字段之前放置了一个常量值,例如 0x12345678。然后,如果一条消息校验和检查失败,您可以通过在数据中查找下一个 0x12345678 来恢复。

尽管该值有时可能出现在消息的中间,但这并不重要。校验和检查很可能会发现该位置没有真正的消息,您可以向前搜索,直到找到下一个标记。

于 2018-07-19T09:37:31.323 回答
1

是否存在任何 protobuf 消息从未使用过的字节序列?

不; 它是一个二进制序列化程序,可以包含任意二进制有效负载(尤其是在bytes类型中)。您不能使用标记值。长度前缀很好(您的“消息大小”标头),校验和可能是一个实用的选项。或者,您可以强加一个人工哨兵来跟踪每条消息(可能是每个连接选择的 guid 作为初始握手的一部分),并使用它来仔细检查一切看起来是否正确。

于 2018-07-19T08:33:57.467 回答