该文简要介绍可靠数据传输中的流水线技术。该技术与停等协议对应,允许发送端发送多个分组而无需等待确认.

可以简要分析一下停等协议的效率:

假设有两台主机,分别位于美国西海岸和东海岸,它们之间的往返传播实验 RTT 大约为 30ms,假定它们通过一条速率 R 为 1Gbps 的信道相连。

包括首部字段和数据的分组长 L 为 1000 bytes(8000 bits),所以发送一个分组进入 1Gbps 链路实际所需时间是: L/R=8us/pkt,即8毫秒一个packet,故在t = RTT/2 + L/R = 15.008ms 时接收端完整的接受到该分组,假设 ACK 分组很小,可以忽略其发送时间,且接收端一旦收到一个数据分组的最后 1bit 后立刻发送 ACK,则 ACK 在时刻 t = RTT + L/R = 30.008ms 时回送到发送端。也就是说,经过 30.008ms 后发送端才可以发送下一个分组。

设利用率为:发送端实际忙于将发送比特送进信道的那部分时间与发送时间之比。
U_sender = (L/R) / (RTT + L/R) = 0.008 / 30.008 = 0.00027
利用率极其低下


流水线技术

使用流水线技术有以下几个注意点:

  • 必须增加序号的范围。因为每个传输中的分组(不计算重传的)必须有一个唯一的序号,而且也许有多个在输送中尚未确认的分组
  • 协议的发送端和接收端也必须缓存多个分组。发送方最低限度应当能缓冲那些已发送但没有确认的分组,接收方或许也需要缓存那些已正确接收的分组
  • 所需序号范围和对缓冲的要求取决于数据传输协议如何处理丢失、损坏和延时过大的分组。

GBN协议

在 GBN 协议中,允许发送方发送多个分组(当有多个分组可用时)而不需等待确认,但它也受限于在流水线中未确认的分组数不能超过某个最大允许数 N。

如下图,显示了发送方看到的 GBN 协议的序号范围。将基序号(base)定义为最早的未确认分组的序号,将下一个序号(nextseqnum)定义为最小的未使用序号(即下一个待发分组的序号),则可将序号范围分割成 4 段。在 [0, base-1] 段内的序号对应于已经发送并确认的分组。[base, nextseqnum-1] 段对应已经发送但未被确认的分组。[nextseqnum, base+N-1] 段内的序号能用于那些要立即发送的分组,如果有数据来自于上层的话。最后,大于或等于 base+N 的序号是不能使用的,直到当前流水线中未确认的分组(特别是序号为 base 的分组)已得到确认为止。

alt

在上图中,把 [base, base+N-1] 看做一个长度为 N 的窗口。随着协议的运行,该窗口在序号空间向前滑动。因此,N 常被称为窗口长度(window size),GBN 协议也常被称为滑动窗口协议(sliding-window protocol)。至于为什么需要限制 N 的范围,是因为这是流量控制的方法之一。

在实践中,一个分组的序号承载在分组首部的一个固定长度的字段中。如果分组序号字段的比特数是 k,则该序号范围是 [0, $2^k - 1$]。在一个有限的序号范围内,所有涉及序号的运算必须使用模$2^k$运算。

GBN发送方事件

上层的调用

当上层调用 rdt_send() 时,发送方首先检查发送窗口是否已满,即是否有 N 个已发送但未被确认的分组。

如果窗口未满,则产生一个分组并将其发送,并相应地更新变量;

如果窗口已满,发送方只需将数据返回给上层,隐式地指示上层该窗口已满。然后上层可能会过一会儿再试。

在实际实现中,发送方更可能缓存这些数据,或者使用同步机制(如一个信号量或标志)允许上层在仅当窗口不满时才调用 rdt_send()。

收到一个ACK

在 GBN 协议中,对序号为 n 的分组的确认采取累积确认(cumulative acknowledgment)的方式,表明接收方已正确接收到序号为 n 的以前且包括 n 在内的所有分组。

超时事件

协议的名字“回退 N 步”来源于出现丢失和时延过长分组时发送方的行为。就像在停等协议中那样,定时器将再次用于恢复数据或确认分组的丢失。

如果出现超时,发送方重传所有已发送但未被确认过的分组。上图中发送方仅使用一个定时器,如果收到了一个 ACK,但仍有已发送但未被确认的分组,则定时器被重新启动。如果没有已发送但未被确认的分组,该定时器被终止。

TODO 怎么理解定时器?

GBN接收方事件

如果一个序号为 n 的分组被正确接收到,并且按序(即上次交付给上层的数据是序号为 n - 1 的分组),则接收方为分组 n 发送一个 ACK,并将该分组中的数据部分交付到上层。

在所有其他情况下,接收方将丢弃该分组,并为最近按序接收的分组重新发送 ACK。

注意到因为一次交付给上层一个分组,如果分组 k 为已接受并交付,则所有序号比 k 小的分组也已经交付。因此,使用累积确认是 GBN 的一个自然的选择。

虽然 GBN 协议看起来很浪费,因为它会丢弃一个正确接收(但失序)的分组。但这样做是有道理的。因为接收方必须将数据按序交付给上层,假设现在期望接收分组 n,而分组 n + 1 却到了,因为数据必须按序交付,所以接收方可能缓存分组 n + 1,然后,在它收到并交付分组 n 后,再将该分组交付到上层。但是,如果分组 n 丢失,则该分组及分组 n + 1 最终将在发送方根据 GBN 重传规则而被重传,所以,接收方只需要直接丢弃分组 n + 1 即可。

这种方法的优点是,唯一需要维护的信息就是下一个按序接收的分组的序号。缺点就是随后对该分组的重传也许会丢失或出错,进而引发更多的重传。

可以看到,GBN 协议本身相对于 rdt 3.0 协议有了长足进步,但是仍然有它自己的性能问题,尤其是当窗口长度和带宽时延都很大的时,流水线中有很多分组更是如此。任何单个分组的差错就能引起 GBN 协议重传大量分组,事实上是很多分组根本没必要重传,所以,有了一个更加优化的协议,就是下面要说的 选择重传(SR) 协议。


我很好奇