13

我即将编写一个通过 TCP 流的消息协议。接收者需要知道消息边界在哪里。

我可以发送 1) 固定长度的消息,2) 大小字段,以便接收者知道消息有多大,或者 3) 唯一的消息终止符(我想这不能在消息中的其他任何地方使用)。

出于效率原因,我不会使用#1。

我喜欢#2,但流有可能不同步吗?

我不喜欢想法#3,因为这意味着接收者无法提前知道消息的大小,并且还要求终止符不会出现在消息的其他地方。

使用#2,如果有可能不同步,我可以添加一个终结器,还是只要发送方程序发送的内容正确,我就可以保证永远不会不同步?有必要做#2#3吗?

请告诉我。

谢谢,jbu

4

7 回答 7

5

您正在使用 TCP,数据包传递是可靠的。因此,连接要么断开、超时,要么您将阅读整条消息。所以选项#2是好的。

于 2009-06-25T23:14:38.667 回答
5

我同意 sigjuice。如果您有一个大小字段,则不需要添加和消息结束分隔符 - 但是,这是一个好主意。两者兼备使事情更加健壮且更易于调试。

考虑使用标准的网络字符串格式,它包括大小字段和字符串结尾字符。因为它有一个大小字段,所以可以在消息中使用字符串结尾字符。

于 2010-07-04T04:30:23.407 回答
3

如果您正在从头开始开发发送和接收代码,那么同时使用长度标头和分隔符不会有什么坏处。这将提供稳健性和错误检测。考虑只使用#2 的情况。如果你在 TCP 流中写入一个长度为 N 的字段,但最终发送的消息的大小与 N 不同,接收端不会更好地了解并最终感到困惑。

如果你同时使用#2 和#3,虽然不是万无一失的,但如果接收者在从 TCP 流中消耗 N 个字节后遇到分隔符,则它可以有更大程度的信心认为它正确接收了消息。您还可以安全地在消息中使用分隔符。

查看 HTTP块传输编码,了解同时使用 #2 和 #3 的真实示例。

于 2009-06-25T23:34:25.163 回答
3

根据您工作的级别,#2实际上可能不会出现不同步的问题(TCP在数据包中有序列号,并且如果流无序到达,它会以正确的顺序为您重新组装流) .

因此,#2 可能是您最好的选择。此外,在传输的早期就知道消息的大小将更容易在接收端分配内存。

于 2009-06-25T23:16:46.993 回答
2

有趣的是这里没有明确的答案。#2 通常在 TCP 上是安全的,并且经常在“现实世界”中完成。这是因为 TCP 保证所有数据都完好无损地到达*并按照发送的顺序到达。

*除非以 TCP 校验和仍然通过的方式损坏。

于 2012-10-09T06:37:49.583 回答
1

回答旧消息,因为有一些东西需要纠正:

与此处声称的许多答案不同,TCP 不保证数据完好无损地到达。甚至实际上都没有。

TCP 协议有一个 2 字节的 crc 校验和,如果超过一位翻转,显然有 1:65536 的碰撞机会。这是一个很小的机会,它永远不会在测试中遇到,但是如果您正在开发的东西要么传输大量数据和/或被非常多的最终用户使用,那么这个骰子就会被抛出数万亿次(不是开玩笑,youtube每个用户每秒抛出大约 30 次。)

选项 2:由于您自己列出的原因,尺寸字段是唯一实用的选项。固定长度的消息会很浪费,并且分隔符标记需要通过某种编码-解码阶段运行整个有效负载,以替换至少三个不同的符号:开始符号、结束符号和表示已发生替换的替换符号。

除此之外,很可能希望使用某种带有严重校验和的错误检查。可能与加密协议一起实现作为消息有效性检查。


至于不同步的可能性:每条消息都有可能,但有补救措施。

一个有用的方案是每条消息都以标头开头。此标头可以非常短(<30 字节),并包含消息有效负载长度、有效负载的最终正确校验和以及标头本身的第一部分的校验和。消息也将具有最大长度。这种短标题也可以用已知符号来定界。

现在接收端将始终处于以下两种状态之一:

  1. 等待新的消息头到达
  2. 接收更多数据到正在进行的消息,其长度和校验和是已知的。

这样,接收方在任何情况下最多会在一条消息的最大长度内不同步。(假设消息长度字段中存在损坏的标头)

使用这种方案,所有消息都作为离散的有效载荷到达,即使中间有恶意破坏的数据,接收方也不会永远卡住,到达有效载荷的长度是预先知道的,并且成功传输的有效载荷已经通过额外的更长校验和来验证,并且校验和本身已经过验证。所有这些的开销可能只是一个包含三个 64 位字段和两个定界符号的 26 字节标头。

(标头不需要替换编码,因为它只在一个正在进行的消息状态中被预期,并且整个 26 个字节可以一次处理)

于 2020-11-18T00:21:34.600 回答
0

还有第四种选择:一种自描述协议,例如 XML。

于 2010-07-04T05:15:50.293 回答