咱们以前介绍SACK选项的时候说过,SACK能够把接收端系列号空间的洞反映给发送端,所以发送端能够更充分的理解接收端的状况,而进行更好的重传恢复过程。这种过程有时候也叫作advanced loss recovery。linux
1、数据接收端SACK行为缓存
咱们经过一个wireshark示例来讲明接收端的SACK行为:tcp
如上图,为了方便在info列中查看SACK信息,我把info列中TSopt的信息隐藏了,同时把源地址列和目的地址列一块儿隐藏了。client依次发送P1(1-6)、P2(25-30)、P3(13-18)、P4(37-42)、P5(49-54)、P6(7-12)、P7(31-36)、P8(19-24)、P9(43-48)其中括号中的数字为相对系列号,接收端SACK行为简述以下(详细的能够参考原始的wireshark文件)ide
接收端在接收到P1后回复的No5确认包中不包含SACK信息测试
在接收到P2后回复的No7确认包中包含的SACK块为(25-31)this
接收端在接收到P3后回复No9确认包,包含的SACK块为(13-19),(25-31)spa
接收端在接收到P4后回复No11确认包,包含的SACK信息为(37-43),(13-19),(25-31)3d
接收端在接收到P5后回复No13确认包,包含的SACK信息为(49-55),(37-43),(13-19),上图截图中对应的SACK信息就是这个确认包的信息server
接收端在接收到P6后回复No15确认包,包含的SACK信息为(49-55),(37-43),(25-31)blog
接收端在接收到P7后回复No17确认包,包含的SACK信息为(25-43),(49-55)
接收端在接收到P8后回复No19确认包,包含的SACK信息为(49-55)
接收端在接收到P9后回复No21确认包,接收端系列号空间中再也不存在洞,由于这个确认包中再也不包含SACK信息。
上面的每一个ACK确认包都会包含一个TSopt的选项,从上面第5点能够看到,在ACK确认包包含有TSopt选项的时候,最后只能包含3个SACK块,此时TCP头长已经到达60bytes的最大值不能在容纳更多的SACK块了。
另外注意就是SACK块是按照最新造成的洞信息倒序排列的。每一个ACK报文中能够携带多个SACK块的缘由是由于ACK确认包有可能会丢包,可是ACK报文不消耗系列号所以不会进行重传,所以接收端经过多个ACK报文中冗余的SACK块信息来提升SACK信息传输的可靠性。
2、数据发送端SACK行为
TCP链接要利用SACK信息还须要发送端根据接收到的SACK信息执行选择性重传(selective retransmisson或者叫作selective repeat)。首先根据SACK信息来填充洞,而后在传递新数据(RFC6675),可是具体实现上可能会有一些差别。另外按照RFC2018,当TCP初始化一个RTO超时重传的时候须要清空SACK信息,可是RFC6675认为RTO超时保留SACK信息也是有必定必要性的。RFC2018还要求发送端只有收到TCP头中的累计ack number的时候才能释放对应的发送缓存,而不能根据SACK信息释放,缘由是接收端有可能先发送一个SACK块,而后后面又不在反馈这个SACK块(SACK reneging)。(实际上按照协议发送端接收到的SACK块多是接收端已经丢弃的TCP报文,虽然这个报文丢弃了可是特定状况下接收端仍然能够在SACK块中携带这个报文信息,而在实现上若是linux内存不足,那么有可能会丢掉已经收到的乱序TCP报文)。SACK reneging的示例咱们后面会在FACK介绍中进行简单介绍。
另一个须要注意的就是在快速重传的时候dup ACK的定义,RFC6675中对于SACK下dup ACK的定义以下
For the purposes of this specification, we define a "duplicate acknowledgment" as a segment that arrives carrying a SACK block that identifies previously unacknowledged and un-SACKed octets between HighACK and HighData. Note that an ACK which carries new SACK data is counted as a duplicate acknowledgment under this definition even if it carries new data, changes the advertised window, or moves the cumulative acknowledgment point, which is different from the definition of duplicate acknowledgment in [RFC5681].
其中
"HighACK" is the sequence number of the highest byte of data that has been cumulatively ACKed at a given point. "HighData" is the highest sequence number transmitted at a given point.
下面咱们仍是重点关注一下Linux实现上的处理吧。
3、SACK下的重传示例
一、SACK打开可是不携带SACK选项的场景
前面咱们介绍快速重传示例的时候,都是把tcp_sack开关设置为0。其中有一个示例以下
其中No12-No14三个数据包是不带有SACK选项的ACK确认包。能够看到server在接收到三个dup ack后触发了快速重传,咱们设置tcp_sack为1后从新运行测试程序,抓包以下,能够看到server在接收到三个不带有SACK选项的dup ack后并无触发快速重传,由此能够看到SACK下对于dup ACK理解上的差别。
二、带有SACK选项的快速重传
下面咱们看一个带有SACK的快速重传,下面的测试程序与上面相似,一样打开tcp_sack功能,不一样的时候此次在No12确认包中包含17-25的SACK块信息,在No13确认包中包含17-33的SACK块信息,在No14确认包中包含17-41的SACK块信息。No12-No14确认包的ack number都是9,在收到No14确认包后累计收到三个dup ACK,所以触发了快速重传。注意这里对dup ACK的认定并非由于ack number相同,而是由于SACK块中累计反馈了三个发送出去的数据包。
三、SACK下ack number不一样的dup ACK
上面咱们说过SACK下对于dup ACK的认定并非由于ack number不一样。咱们在来看一个例子,从下图能够看到wireshark显示两个dup ack后就触发了快速重传,其实是由于wireshark对于dup ack的认定只关注ack number致使的。在No11中带有17-25的SACK块信息,No12中带有17-33的SACK块信息,No13中带有17-41的SACK块信息。按照上面SACK下对于dup ACK的定义,server实际上已经接收到了3个dup ACK,所以触发了快速重传。