万字详文:TCP 拥塞控制详解( 三 )


因为单纯忽略重传数据时,如果在某一时间,网络闪动,突然变慢了,产生了比较大的延时,这个延时导致要重转所有的包(因为之前的 RTO 很小),但因为重转的不算,RTO 就不会被更新,这是个灾难 。而且一发生重传就对现有的 RTO 值翻倍的方式也很难估算出准确的 RTT 。
3.1.4 TCP 时间戳选项(TSOPT)
根据 [RFC1323],TSOPT 主要有两个用途,一个是 RTTM(round-trip time measurement),即根据 ACK 报文中的这个选项测量往返时延;另外一个用途是 PAWS(protect against wrApped sequence numbers),即防止同一个连接的系列号重叠 。另外还有一些其他的用途,如 SYN-cookie、Eifel Detection Algorithm 等等 。TSOPT 为 Options 选项中一种,格式如下:
Kind: 8Length: 10 bytes+-------+-------+---------------------+---------------------+Kind=8 |10|TS Value (TSval)|TS Echo Reply (TSecr)|+-------+-------+---------------------+---------------------+1144RTT 测量(RTTM)
当使用这个选项的时候,发送方在 TSval 处放置一个时间戳,接收方则会把这个时间通过 TSecr 返回来 。因为接收端并不会处理这个 TSval 而只是直接从 TSecr 返回来,因此不需要双方时钟同步 。这个时间戳一般是一个单调增的值,[RFC1323]建议这个时间戳每秒至少增加 1 。其中在初始 SYN 包中因为发送方没有对方时间戳的信息,因此 TSecr 会以 0 填充,TSval 则填充自己的时间戳信息 。
防回绕序列号(PAWS)
TCP 判断数据是新是旧的方法是检查数据的序列号是否位于 sun.una 到 sun.una + 的范围内,而序列号空间的总大小为,即约 4.29G 。在万兆局域网中,4.29G 字节数据回绕只需几秒钟,这时 TCP 就无法准确判断数据的新旧 。
PAWS 假设接收到的每个 TCP 包中的 TSval 都是随时间单调增的,基本思想就是如果接收到的一个 TCP 包中的 TSval 小于刚刚在这个连接上接收到的报文的 TSval,则可以认为这个报文是一个旧的重复包而丢掉 。时间戳回绕的速度只与对端主机时钟频率有关 。Linux 以本地时钟计数(jiffies)作为时间戳的值,假设时钟计数加 1 需要 1ms,则需要约 24.8 天才能回绕一半,只要报文的生存时间小于这个值的话判断新旧数据就不会出错 。
SYN Cookie 的选项信息
TCP 开启 SYNCookie 功能时由于 Server 在收到 SYN 请求后不保存连接,故 SYN 包中携带的选项(WScale、SACK)无法保存,当 SYN Cookie 验证通过、新连接建立之后,这些选项都无法开启 。
使用时间戳选项就可以解决上述问题 。将 WScale 和 SACK 选项信息编码进 32 bit 的时间戳值中,建立连接时会收到 ACK 报文,将报文的时间戳选项的回显信息解码就可以还原 WScale 和 SACK 信息 。
3.2 Fast Retransmit(快速重传)快速重传算法概括为:TCP 发送端在观测到至少 dupthresh(一般为 3) 个重复 ACK 后,即重传可能丢失的数据分组,而不需等待重传计时器超时 。
3.2.1 SACK 重传

  1. 未启用 SACK 时,TCP 重复 ACK 定义为收到连续相同的 ACK seq 。[RFC5681]
  2. 启用 SACK 时,携带 SACK 的 ACK 也被认为重复 ACK 。[RFC6675]
如下图所示(绿色为已发送并且被 ack 的数据包,黄色表示已发送还未确认的数据包,浅绿色为被 Sack 确认的数据包,蓝色表示还未发送的数据包),设 dupthresh = 3,SACKed_count = 6,从 unAcked 包开始的 SACKed_count - dupthresh 个数据包,即 3 个数据包会被标记为 LOST 。
万字详文:TCP 拥塞控制详解

文章插图
拥塞窗口状态
记分板状态如下,红色表示该数据包丢失:
万字详文:TCP 拥塞控制详解

文章插图
记分板状态
3.2.2 FACK 重传FACK 是 SACK 的一个激进版本,它拥有标准 SACK 算法的一切性质,除此之外,它假设网络不会使数据包乱序,因此收到最大的被 SACK 的数据包之前,FACK 均认为是丢失的 。FACK 模式下,重传时机为 被 SACKed 的包数 + 空洞数 > dupthresh 。
如下图所示,设 dupthresh = 3,FACKed_count = 12,从 unACKed 包开始的 FACKed_count
  • dupthresh 个数据包,即 9 个包会被标记为 LOST 。

万字详文:TCP 拥塞控制详解

文章插图
拥塞窗口状态
记分板状态如下,红色表示该数据包丢失:
万字详文:TCP 拥塞控制详解

文章插图
记分板状态
3.2.3 RACK 重传
基本思路 如果数据包 p1 在 p2 之前发送,没有收到 p1 的确认,当收到 p2 的 Sack 时,推断 p1 丢包 。算法简介 每一个 skb 记录发送时间 xmit_time,传输控制块维护全局变量:rack.xmit_time,rack.reo_wnd 。rack.xmit_time 是接收方已经收到的最新的那个 skb 的发送时间,rack.reo_wnd 是乱序的时间窗口大小 。


推荐阅读