TCP/IP卷一:75---TCP超时与重传之(带选择确认选项(SACK)的选择性重传)
作者:互联网
一、带有选择确认选项的重传
- TCP选择确认选项(SACK):https://blog.csdn.net/qq_41453285/article/details/104039845
- 随着选择确认选项的标准化,TCP接收端可提供SACK功能,通过TCP头部的累积ACK号字段来描述其接收到的数据。之前提到过,ACK号与接收端缓存中的其他数据之间的间隔称为空缺。序列号高于空缺的数据称为失序数据,因为这些数据和之前接收的序列号不连续
采用SACK的好处
- TCP发送端的任务是通过重传丢失的数据来填补接收端缓存中的空缺,但同时也要尽可能保证不重传已正确接收到的数据
- 在很多环境下,合理采用SACK信息能更快地实现空缺填补,且能减少不必要的重传,原因在于其在一个RTT内能获知多个空缺
使用SACK的相关概念
- 当采用SACK选项时,一个ACK可包含三四个告知失序数据的SACK信息。每个SACK信息包含32位的序列号,代表接收端存储的失序数据的起始至最后一个序列号(加1)
- SACK选项指定n个块的长度为8n+2字节,因此40字节可包含最多4个块
- 通常SACK会与TSOPT一同使用,因此需要额外的10个字节(外加2字节的填充数据),这意味着SACK在每个ACK中只能包含3个块。3个块表明可向发送端报告3个空缺。若不受拥塞控制限制,利用SACK选项可在一个RTT时间填补3个空缺。包含一个或多个SACK块的ACK有时也简单称为“SACK”
二、SACK接收端行为
- 接收端在TCP连接建立期间收到SACK许可选项即可生成SACK。通常来说,每当缓存中存在失序数据时,接收端就可生成SACK
- 导致数据失序的原因可能是:
- 由于传输过程中丢失
- 也可能是新数据先于旧数据到达
- 这里只讨论第一种情况,后一种留待以后再讨论
不同SACK块的内容
- 在上面介绍我们知道一个含有SACK选项的ACK,可以将SACK分为好几个块:
- 第一个SACK块内包含的是最近接收到的报文段的序列号范围。由于SACK选项的空间有限,应尽可能确保向TCP发送端提供最新信息
- 其余的SACK块包含的内容也按照接收的先后依次排列
- 也就是说,最新一个块中包含的内容除了包含最近接收的序列号信息,还需重复之前的SACK块(在其他报文段中)
在一个ACK中包含多个SACK块的目的
- 在一个SACK选项中包含多个SACK块,并且在多个SACK中重复这些块信息的目的在于,为防止SACK丢失提供一些备份
- 若SACK不会丢失,[RFC2018]指出每个SACK中包含一个SACK块即可实现SACK的全部功能。不幸的是,SACK和普通的ACK有时会丢失,并且若其中不包含数据(SYN或FIN控制位字段不被置位)就不会被重传
三、SACK发送端行为
- 尽管一个支持SACK的接收端可通过生成合适的SACK信息来充分利用SACK,但还不足以使该TCP连接充分利用SACK功能。在发送端也应提供SACK功能,并且合理地利用接收到的SACK块来进行丢失重传,该过程也称为选择性重传或选择性重发
发送端的工作原理
- 避免重传正确数据:
- SACK发送端记录接收到的累积ACK信息(像大多数TCP发送端一样),还需记录接收到的SACK信息,并利用该信息来避免重传正确接收的数据
- 一种方法是当接收到相应序列号范围的ACK时,则在其重传缓存中标记该报文段的选择重传成功
- 当SACK发送端执行重传时,通常是由于其收到了SACK或重复ACK,它可以选择发送新数据或重传旧数据。SACK信息提供接收端数据的序列号范围,因此发送端可据此推断需要重传的空缺数据。最简单的方法是使发送端首先填补接收端的空缺,然后再继续发送新数据[RFc3517](若拥塞控制机制允许)。这也是最常用的方法
一个特殊情况
- 该行为有一个例外。在[RFC2018]中,SACK选项和SACK块的当前规范是建议性的。这意味着接收端可能提供一个SACK告诉发送端已成功接收一定序列号范围的数据,而之后做出变更(“食言”)。由于这个原因,SACK发送端不能在收到一个SACK后立即清空其重传缓存中的数据;只有当接收端的普通TCP ACK号大于其最大序列号值时才可清除
- 这一规则同样影响重传计时器超时的行为。当TCP发送端启动基于计时器的重传时,应忽略SACK显示的任何关于接收端数据失序的信息。如果接收端仍存在失序数据,那么重传报文段的ACK中就包含附加的SACK块,以便发送者使用。幸运的是,食言情况很少出现,也应尽量避免出现
四、演示案例
- 为理解SACK怎样影响发送端和接收端的行为,我们重复前面的快速重传实验,参数设置也如前(丢掉序列号23601与28801),但这次发送端和接收端都采用SACK。为准确观测到实验过程,我们仍采用Wireshark的TCP序列号图功能(见下图)
- 上图与前面“快速重传”文章中的例子类似,但利用SACK信息,发送端在重传完报文段23601后,不必等待一个RTT再重传丢失报文段28801。后面将仔细讨论这些内容,现在我们首先在连接建立过程中验证SACK允许(SACK-Permitted)选项的存在,见下图
- 与预计的一样,接收端通过SACK允许选项来使用SACK。发送端的SYN包,即记录的第一个包,也包含了该选项。这些选项只在连接建立阶段才能看到,因此只出现在SYN 置位的报文段中
- 一旦连接被允许使用SACK,发生丢包即会使得接收端开始生成SACK。Wireshark显示了第一个SACK选项的内容(见下图)
- 下图显示了首个SACK被接收后的一系列事件。wireshark通过SACK范围的左右边界来表示SACK信息。这里我们看到23801的ACK包含了一个SACK块[25201, 26601],指明接收端的空缺。接收端缺失的序列号范围为[23801,25200],相当于一个从序列号23801开始的1400字节的包。注意到该SACK为一次窗口更新,并不能算作重复ACK,之前也提到过,因此不能触发快速重传
- 0.967s时刻到达的SACK包含两个块:[28001, 29401]和[25201, 26601]。回忆一下前面提过的,为提高对ACK丢失的鲁棒性,第一个SACK块中需要包含之前的重复SACK信 息。该SACK为序列号23801的重复ACK,表明接收端现在需要从序列号23801至26601的两个全长报文段。发送端立即响应,启动快速重传,但由于拥塞控制机制,发送端只重传了一个报文段238010随着另外的两个ACK的到达,发送端被允许发送第二个重传报文段26601
- TCP SACK发送端借鉴了NewReno算法中的恢复点的思想。本例中,在重传前发送的 最大序列号为43400,低于“基于计时器重传”的演示案例中所示的NewReno算法的例子。这里的SACK快速重传实现中,不需要三次重复ACK;TCP更早地启动了重传,但恢复的出口本质上是一致的。一 旦接收到序列号43401的ACK,即1.3958s时刻,恢复阶段即完成。
- 值得注意的是,发送端采用sACK并不能百分百地提高整体传输性能。我们来看之前讨 论过的这两个例子,NewReno发送端(非SACK)完成131 074字节的数据传输用时3.529s,而SACK发送端则用了3.674s。尽管这两个值不能这样直接比较,因为两者所处的网络环境并非绝对相同(这不是仿真实验,而是在真实环境中的测试),但极为近似。在RTT较大,丢包严重的情况下,SACK的优势就能很好地体现出来,因为在这样的环境下,一个RTT内能填补多个空缺显得尤为重要
![](https://g.csdnimg.cn/static/user-reg-year/1x/2.png)
标签:重传,接收端,ACK,IP,SACK,发送,TCP,序列号 来源: https://blog.csdn.net/qq_41453285/article/details/104100004