TCP 实现是否重新传输字节或段?

网络工程 通讯协议 协议理论
2021-07-20 06:56:41

TCP 标头中的序列号和确认号被指定为包含字节计数。但是,包括 RFC 在内的许多资源都说“重新传输丢失的段”而不是“重新传输丢失的字节”。

例如,如果发送了 4 个 500 字节的段并且第 2 和第 3 段丢失了,是否允许将字节 500-1500(之前在第 2 和第 3 段中发送)作为一个段重新传输?如果是,作为一个段重传的优缺点是什么?有没有常见的实现呢?在这里,我假设 MTU 对于组合包始终足够大(分开传输第 2 和第 3 段的原因可能是例如禁用了 Nagle 算法)。

是否使用选择性确认对这个问题有影响吗?需要选择性确认以避免重传第 4 段。但是在这种情况下它是否有任何其他影响(在第 2 和第 3 段)?

查看Linux内核源代码,它似乎将段放入输出队列。它可以细分已经在队列中的段(在 MTU 减少的情况下)。在 TCP 实现中,我没有看到任何将较小段重新组装成较大段的代码。但是我可以想象 TCP 分段卸载 (TSO) 可能会导致传输更大的分段。我不知道是否有可能找出确切的分割边界。从协议理论的角度来看会有什么好处吗?

3个回答

发送方 TCP 接收来自上层应用程序的字节流,并将该流分成一系列段。当一个段被发送时,一个重传计时器启动。如果在重传定时器超时之前没有收到相当于段中最后一个字节的 ACK,则重新发送整个段。

接收器不能确认一个段的一部分,因为如果没有接收到整个段,它就无法计算校验和并确定该段是否已损坏。所以接收器只会确认整个段,如果它以某种方式接收到一个段的一部分,它会将其视为损坏的并且不确认任何段。因此,发送方只重传完整的段。

就组合顺序重传段而言,这些段保存在重传队列(或指向数据的指针)中,并且发送方 TCP 不希望对该数据进行任何进一步处理,它只会按原样发送它们,如果重传定时器超时,将不会有段合并。

TCP RFC 的摘录证实了这一点:

当 TCP 传输一个包含数据的段时,它会在重传队列中放置一个副本并启动一个计时器;当收到对该数据的确认时,该段将从队列中删除。如果在定时器用完之前没有收到确认,则重新传输该段。

如您所见,没有提及重新组合数据,仅重新发送原始段。

是的,在您的示例中,选择性 ACK 很重要,没有它们,只有第一个段可能是 ACK,最后三个将被重新传输。

发送方可以根据自己的选择重新传输段(或本质上是字节)。但是,它可能会选择路径/链路 MTU 可能的最大分段大小,因此不太可能将先前单独传输的两个分段组合在一起 - MTU 或 MSS 不会即时更改。

编辑:如果发送方使用的带宽比通道提供的带宽低得多,则可能没有使用 MSS(或 MTU)并且实际发送的段要小得多。在这种情况下,发送方可以在重新发送时将两个段的数据合并为一个段。但是,我认为这并未得到广泛实施。

如果节省开销(报头数据空间)并因此提高效率并减少使用的带宽,则传输更大的段有好处。因此,应始终使用尽可能大的段大小。

TCP 中沿流的度量单位是字节。重传的义务是重新提供相同的字节。分割可以改变。

将标准律师的帽子换成实现者的帽子,您可能会问“但重新传输相同的字节会不会导致将这些字节组装成与原始传输中相同的段?” 答案是“为什么是的,它会”。如果他们选择利用这些知识来提高效率,则取决于实施者。