前言

TCP是个可靠的协议,网络又是复杂不可控的环境,那么如果出现发送包丢失、校验失败接收包丢弃、回复ACK丢失等等请求都需要发送方进行重试。具体TCP实现上有哪些机制保障了消息及时准确的重试,希望文章能解答这个问题。


为什么要重传

其实前言已经提到了,在包各种丢失的场景中,TCP又要保障所有包必须到达,所以需要有重传机制

这里有两个前提先声明下:

  • TCP首部中SeqNum和ACK的值是以字节数为单位。
  • ACK的值表示之前的Segment都已经收到了,期待的下一个Segment的Seq值。

重传的方式

正常的场景:

再看一个异常场景:
发送方发送5个数据包,包1、包2、包3、包4、包5,假如接收方收到了包1、包3、包4、包5,此时包2未收到,TCP应该如何处理?

常见的重传机制包括:

  • 超时重传
  • 快速重传
  • SACK
  • D-SACK

超时重传

所谓超时重传,发送方发出的包一直收不到ACK,超过一定时间,触发重传对应的包。

超时时间的计算算法看后面的文章,目前知道有这么个时间。

收不到ACK有可能:

  • 发出去的包丢了,接收方未收到
  • 接收方收到了包,回复的ACK丢了

例如,包1到了回复ACK,包2未到,包3到了。一种方式是接收方不回包3的ACK,等待发送端包2的到达。直达发送发超时。

此时发送方面临两种重传选择

  • 仅仅包2超时了,重传包2的Segment数据
  • 重传包2及后面的所有包数据,因包3没有ACK,即便已经收到了,发送方也很不知道咋回事

第一种会节省带宽,但是可能包3也丢了,都等超时整个过程比较慢;第二种一起重传可能浪费了带宽,但是整体缩短了,但也可能因为后面的包没丢浪费了带宽。

小结:不管哪种方式,都不怎么好,发送方知道的太少了,而且需要等待包超时。


快速重传

TCP出现了一种快速重传的机制,叫Fast Retransmit。如果出现丢包,后续的包到达,接收方进行ACK希望收到的包,发送方连续收到重复的ACK,如果出现3次重复的ACK,进行快速重传。

这是一种接收方给发送方的信号,给到我想要的包。

如图所示,当发送方连续收到3个相同的ACK时,便会进行快速重传对应的包。

这里的重复次数“3”不包括收到正常的ACK的那次。

小结:快速重传解决了时间问题,仍然面临着重传哪些包的问题,因为导致duplicate ACK的包并没有什么规律。另外,有可能丢包后的duplicate不够3次,so,超时重传机制要有。


SACK方法

SACK(Selective Acknowledgment)选择性确认,这个SACK是TCP首部的Options中的类型,表示了收到的数据碎块,即已经收到的数据。

image-1702128127233

如图所示:发送方能清晰的知道哪些包已经到了,哪些包需要重传(200-299,400-499)。

小结:SACK成功解决了快速重传中的问题,这个选项需要双端都支持。默认Linux2.4下打开,参数是net.ipv4.tcp_sack

注意,这里有个概念叫接收方Reneging,即接收方可能把发回给发送方SACK的数据弄丢,它不能代表ACK,例如内存太够的情况下。所以发送方不能依赖SACK来决定后续要不要发送,一切还是要看ACK的值。so,超时重传机制要有。


D-SACK

D-SACK即Duplicate SACK,用来告诉发送方收到了哪些重复的SACK

TCP首部没有单独的D-SACK,它还是SACK选项,只是将重复的SACK称为D-SACK:

  • 当SACK的第一个Seq号区间小于ACK号,那么它就是D-SACK。

场景举例如下:

ACK丢失

图中,最后一个回复可知ACK 300之前的数据都收到了,SACK 100-200是属于重复发送的数据。因为ACK 300发送端没有收到过(这是关键点),所以这时候发送端就知道是ACK丢失了

网络延迟

如图,包200-299在网络中迷失,其它的包都到了,通过3次重复ACK触发了快速重传且收到了单独的ACK 500;而后原来在网络中延迟的包到达,此时接收端ACK 500时增加SACK 200-300表示重复收到数据。因为ACK 500发送端已经收到过(这是关键点),所以这时候发送端就知道是发送的包有延迟

引入了D-SACK,有一些好处,如下:

  • 可以让发送方知道是发出的包丢了,还是回来的ACK丢了。
  • 网络上是不是出现了先发的包后到的情况(又叫recording)。
  • 网络上是不是把发送方的数据包进行复制发送了。

小结:D-SACK对于帮助TCP了解网络状况很有帮助,TCP可以更好的进行流量控制。默认Linux2.4下打开,参数是net.ipv4.tcp_dsack


总结

TCP的重传机制包括了超时重传、快速重传、SACK、D-SACK。他们并不是相互独立的,例如超时重传机制是最基础也是TCP可靠传输的保障,其它的几种机制则是应对特殊场景一步步进化而来,能够帮助TCP知道更多的细节。网络是复杂的,优化手段也要跟着不断升级。