一、概述

forward retransmit相关的内容在RFC6675中有描述,可以参考RFC6675 section 4中NextSeg ()的定义。forward retransmit中文名可以叫做前向重传,我这里简单说一下linux实现上的前向重传

在快速重传(包括快速重传的各种变种)到达Recovery point之前,都会尝试重传标记为lost的数据包,当把标记为lost的数据包重传完毕后,如果同时满足下面几个条件:

1、当前拥塞控制处于Recovery状态,且在尝试重传数据包的时候,拥塞窗口允许TCP传输数据包

2、TCP连接没有待发送的数据包或者受限于window size、nagle算法等而不能发送

3、TCP连接支持SACK功能

当同时满足上面三个条件的时候,如果已经被SACK确认的最高的系列号与当前已经重传过的数据包之间存在未被SACK确认且未重传过的数据包,那么TCP就会尝试前向重传这些未进行过重传的数据包。

其实前向重传并不复杂,但是前向重传相比其他的重传方式在拥塞控制时候有自身的特殊性,后续介绍拥塞控制的时候进行介绍,下面我们通过wireshark来看一个具体示例。

二、wireshark示例

1、forward retransmit简单示例

在进行下面的测试前需要设置tcp_recovery=0,以关闭RACK重传机制,RACK重传优先于前向重传,因此当打开RACK的时候,RACK会先起作用把数据包标记为lost,并进行重传。后续文章介绍RACK。

业务场景:server端与client端建立连接休眠1000ms后,以3ms为间隔连续发送9个数据包No4-No12,每个数据包的大小为50bytes,其中只有No4和No11数据包成功到达接收端,其余数据包均在传输过程中丢失,我把传输丢失的数据包设置了高亮显示。

No1-No3:client与server端建立连接,SYN报文中协商了MSS=62,扣除TSopt选项的12bytes后,server端最多只能传输50bytes的数据,因此server端在重传的时候不会进行重组包(后续详细介绍)。

No4-No12:server端发出对应的数据包,其中只有No4和No11成功传输到client端。其实数据包传输过程中丢失。

No13:对应No4报文的ACK确认包

No14-No15:对应No11报文的ACK确认包,可以看到这是一个dup ACK,此时fackets_out=7,dupthresh=3,fackets_out-dupthresh=4。因此server端把No5、No6、No7、No8这四个数据包标记为lost。接着server端先重传No5数据包,受限于拥塞控制,其余数据包暂时还不能进行重传。

No16-No18:server端收到No16这个确认包后,拥塞控制进行更新,允许server端发出两个数据包,因此server端接着重传No6和No7数据包,即对应No17和No18。

No19-No20:server端收到No19后,拥塞控制允许发出一个数据包,因此server端重传No8数据包,即对应No20。

No21-No22:server端收到No21后,拥塞控制进行更新后允许发出一个数据包,此时被标记为lost的4个数据包都已经进行了重传,同时server端也没有新数据等待发送,因此server端进行前向重传,重传No9数据包,这里注意No9数据包并没有被标记为lost,但是同样进行了重传。

No23-No24:这组数据包的处理与No21-No22类似。

No25:server端收到No25的时候,虽然拥塞控制允许发出数据包,但是此时被SACK确认的最高系列号为401(实际上是最高系列号的下一个系列号),在系列号401之前已经没有未被SACK确认且未重传过的数据包了,因此尝试前向重传失败,没能发出数据包。这里可以看到虽然No12数据包也丢失了,但是前向重传并不会重传No12。

No26:server端收到No26后重启RTO定时器,定时时间大约为250ms

No27-No28:RTO超时后把No27标记为lost,并重传No27,接着收到No27的确认包,整个传输过程结束。

TCP系列22—重传—12、Forward Retransmit-LMLPHP
05-12 07:12