Page 431 - 《软件学报》2024年第4期
P. 431
李彤 等: 传输控制中的确认机制研究 2009
时延信息、接收缓存中接收但未提交到上层应用的数据量等. 作为扩展, 只要整个 TACK 报文不超过 MSS,
TACK 还可以携带历史丢包信息等. 这些历史丢包信息并不是必选的, 可以按需携带. 具体地, Li 等人 [29] 给出了反
′
ρ 满足以下条件时, TACK 报文需要携带更多的历史丢包信息:
向路径上的丢包率
Q·MSS
, BDP ⩾ β· L·MSS
ρ· BDP
′ ,
ρ >
Q
, BDP < β· L·MSS
ρ· L
′
其中, Q 表示 ACK 携带的信息量, ρ 表示正向路径上的丢包率, ρ 表示反向路径上的丢包率. 更进一步, 当 BDP ⩾
ρ·ρ · BDP
′
′
β· L·MSS 时, 需要增加的信息量为 − Q ; 当 BDP < β· L·MSS 时, 需要增加的信息量为 ρ·ρ · L− Q .
MSS
(3) 丢包驱动的 IACK 报文
接收方通过丢包驱动的 IACK, 可以主动拉取丢失的数据包. 数据包丢失后会重传, 但重传包也可能会丢失.
为了在接收端能够成功地检测丢失的重传包数目, TACK 机制要求每个报文除了携带一个与 TCP 相同定义的数
据序号 (用 DATA.SEQ 表示) 以外, 还需要额外引入一个严格递增的报文序号 (用 PKT.SEQ 表示), 作为每个报文
的一个属性. 也就是说, 先发的报文 PKT.SEQ 小, 后发的报文 PKT.SEQ 大. 对于一个原始报文和其对应的重传报
文, 两者的 DATA.SEQ 相同, 但是 PKT.SEQ 不同. 结合 PKT.SEQ 这一新的数据报文属性, 发送端在收到丢包驱动
的 IACK 时, 就可以明确地知道具体哪个数据包 (包括是否是重传包) 已丢失, 从而提高丢包恢复效率. 值得注意的
是, DATA.SEQ 是必要的, 因为它保证了报文的有序组装.
另一方面, PKT.SEQ 也是必要的. 下面给一个例子说明: 发送端发送 5 个数据报文, 其字节范围为 [0–5999]
(MSS=1500 byte). 假设 PKT.SEQ = 2 的报文 [1500–2999] 丢失, 后续 PKT.SEQ = 3 的报文 [3000–4499] 到达接收
方, 接收方判断丢包事件后通知发送端, 发送端重传 PKT.SEQ = 4 的报文 [1500–2999]. 假设 PKT.SEQ = 4 报文再
次丢失, 当其后续 PKT.SEQ = 5 的报文 [4500–5999] 到达接收方时, 接收方仍然可以通过乱序的 PKT.SEQ, 检测丢
包事件. 然而, 如果没有 PKT.SEQ, 接收端很难检测到底有多少个重传报文又丢失了.
如果接收端检测到前后两个数据报文的 PKT.SEQ 差值大于 1, 会进行丢包事件检测, 如果检测到发生了丢包
事件, 就发送 IACK 报文. 该 IACK 报文携带一个 PKT.SEQ 丢失区间, 该区间指示接收缓存中最大的 PKT.SEQ 和
第 2 大的 PKT.SEQ. 期间的差值就表明哪些数据报文在网络中丢失. 发送端解析此区间, 可以准确找到对应的报
文并重传.
4.1.4 讨论: 滑动窗口与行头阻塞
(1) 滑动窗口机制概述
为了保证数据报文的可靠交付, 如果采用发送方每发出一个数据报文后, 必须等待收到确认该报文的 ACK 报
文后开始发送下一个数据报文, 就变成了一种“停止-等待”协议. 由于上一个报文会阻塞下一个报文的发送, 这种
协议通常效率低下. 因此, TCP 采用滑动窗口机制来提高数据传输效率. 滑动窗口允许发送方一次性发送不超过该
窗口大小的数据, 窗口范围内的后序报文无需等待前序报文的 ACK, 这个窗口的最大值就是发送窗口 (SWND).
通常发送窗口取拥塞窗口 (CWND) 和接收窗口 (RWND) 两者的较小值. 当可发送数据的窗口消耗殆尽时, 就需要
等待; 此时如果收到 ACK 确认应答后, 当前窗口又会向前滑动, 为发送下一批数据报文腾出窗口.
假设某个数据报文丢失, 迟迟未收到相应 ACK, 在该报文对应的重传没有成功之前, 滑动窗口都无法滑动, 这
样就阻塞了后续所有数据报文的发送. 这就是 TCP 滑动窗口机制中的行头阻塞 (head-of-line blocking, HoLB)
问题.
(2)TACK 机制如何解决行头阻塞问题?
造成队头阻塞的根本原因, 是由滑动窗口的定义决定的. 换句话说, 队头阻塞的根本原因是经典 TCP 的滑动
窗口往前滑动的必要条件是发送窗口中 DATA.SEQ 最小的报文 (即滑动窗口的左边界) 得到确认. 因此, 即使
TCP SACK 选项能够确认发送窗口中非连续的后序报文, 但这只能减少不必要的重传, 对滑动窗口的滑动也没有
任何实质的帮助.