- 对每个连接,TCP管理4个不同的定时器。
- 重传定时器
- 坚持定时器
-
保活(keep alive)定时器
检测一个空闲连接的另一端何时崩溃或者重启。 - 2MSL定时器
测试一个连接处于TIME_WAIT
状态的时间。
超时重传
TCP提供可靠的运输层,它使用的方法就是确认另一端收到的数据。但数据和确认都有可能丢失,TCP通过在发送时设置一个定时器来解决这个问题,如果当定时器溢出时还没有收到确认,它就重传该数据。
- 举个重传的例子:
- Server 发送80个字节到Part1,seq = 1。
- Server 发送120个字节Part2,seq = 81。
- Server 发送160个字节Part3,seq = 201,此包丢失。
- Client收到前2个报文段,并发送ACK=201。
- Server发送140个字节Part4,Seq = 361。
- Server发送140个字节Part4,Seq = 361。
- Server 收到 Client 对于前两个报文段的ACK,将2个报文段从窗口中移除,窗口有200个字节的余量。
- 报文3的重传定时器到期,没有收到ACK,Server重传报文3
- 这时候Client已经收到报文4,存放在缓冲区中,也不会发送ACK,等待报文3,报文3收到之后,一块对3和4进行确认。
- Server收到确认之后,将报文3,4移除窗口,所有数据发送完成。
SACK
在上面过程中,会面临一个问题:客户端在等待报文3的时候,服务器如何处理报文4,客户端这个期间内并没有发送任何报文,服务器并不知道报文3和报文4的状态,报文4可能会丢失,也可能会被客户端接收,那么如果超时,是该发哦是哪个报文3,还是报文3和报文4。
总结起来就是2种处理:
- 定时器溢出,重传3。
- 定时器溢出,重传3,4。
对于怎么传的问题,在RFC2018中提供一种方案:SACK。
重传时间计算
快速重传机制
在超时重传中,重点是定时器溢出超时了在认为发送的数据包丢失,快速重传机制,实现了另外的一种丢包评定标准,即如果我连续收到3次 dup ACK,发送方就认为这个seq的包丢失了,立刻进行重传。这样,如果接收端回复及时的话,基本就是在重传定时器到期之前,提高了重传的效率。
在传输过程中会出现out-of-order的现象,但是在滑动窗口中会有严格的顺序控制,假设有4,5,6三个待接收的数据包,先收到5,6。协议栈是不会回复对5,6的包的确认,而是根据TCP的协议规定,当接收方收到乱序片段时,需要重复发送ACK,在这个地方会发送报文4 的ACK,
表明需要报文4没有被接收到,如果此后收到的是报文7,那么仍然要回报文4的ACK,如果连续收到3个dup ACK,发送端就认为这个片段已经丢失,进行快速重传。
在第5个报文之后,我们从 bsdi 发送 "svr4 and hi(换行)" 一共8个字符,在发送前断掉网线。抓包如下:
我们发现,一共重传了13次(6~18),最后发送RST复位给对端。然后检查重传之间的时间差为1, 3, 6, 12......这个倍乘关系被称为指数退避(exponential backoff )
首次分组传输(第6行,24.480秒)与复位信号传输(第19行,566.488秒)之间的时间差约为9分钟,该时间在目前的TCP实现中是不可变的。