如果 tcp 客户端向 tcp 服务器发送一个序列号从 10000 到 20000 的数据包。tcp 将以 seq_ack 20001 的 ACK 响应。
如果我拦截来自客户端的 TCP 数据包,并将数据包分成 2 个 tcp 段,一个 seq 从 10000 到 15000,另一个 seq 从 15001 到 20000。然后这 2 个 TCP 段被发送到 TCP 服务器。假设第二段在路径中丢失。TCP 服务器将使用 seq_ack 15001 响应 ACK。
现在,由于 TCP 客户端发送了一个 seq 10000 到 20000 的完整数据包,但它收到了 15001 的 ACK,从客户端的角度来看,这很奇怪。它会如何反应?理论上,客户端应该重传seq 15001到20000的字节,即客户端会从seq 15001传输新的数据包。但实际情况如何,在TCP堆栈实现中,是否和理论上一样?
我认为在 TCP 发送缓冲区中,当发送一个 tcp 段时,该段仍然停留在那里,直到 ACK。当 ACK 到来时,该段的这些字节将从缓冲区中清除。发送缓冲区中有一个指针,当一个ACK来的时候,指针指向ack_seq对应的位置。ack_seq 之下的字节被清除。这样整个段就不用重传了吧?
这称为选择性确认,并且已经包含在RFC 2018 中定义的 TCP 规范中。这将允许客户端确实重新发送 15001 到 20000 字节(因为如果您按照您所说的方式拆分它们,它们将位于不同的数据包/段中),但更有趣的是,它甚至允许无序确认。
来自 RFC 2018:
当接收到包含 SACK 选项的 ACK 时,数据发送方应该记录选择性确认以供将来参考。假设数据发送方有一个重传队列,其中包含已发送但尚未确认的段,按序列号顺序排列。
支持SACK
是不是由TCP规范要求。如果客户端或服务器不支持选择性确认,则实际上所有 10000 到 20000 字节都必须重新传输。
在TCP栈实现中,和理论上一样吗?
通常SACK
是受支持的,因为性能、效率和延迟增益是显着的——尤其是在像互联网这样的网络中。
然而,事实上,即使您如您所说的那样手动操作数据包,这些假设也应该成立。根据RFC 793,至少必须重新传输整个数据窗口,但接收者确实知道接收到的数据至少是有效的。有关实现细节,请参阅第 3.3 节 - RFC 793 中的序列号。
有关有和没有选择性确认支持的整个过程的概述,请参阅本文(其中包含一些非常有用的图表)。