TCP协议之重传机制
前言
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中的类型,表示了收到的数据碎块,即已经收到的数据。
如图所示:发送方能清晰的知道哪些包已经到了,哪些包需要重传(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知道更多的细节。网络是复杂的,优化手段也要跟着不断升级。