《计算机网络:自顶向下方法》:流水线可靠数据传输

1. 流水线技术

流水线可靠数据传输协议允许发送方发送多个分组而无需等待确认。流水线技术对可靠数据传输协议带来如下影响:

  • 必须增加序号范围,因为每个输送中的分组(不计算重传的)必须有一个唯一的序号,而且也许有多个在输送中未确认的报文。
  • 协议的发送方和接受端也许必须缓存多个分组。发送方最低限度应当能缓存那些已发送但没有确认的分组。接收方也需要缓存那些已正确接受的分组。
  • 所需序号范围和对缓存的要求取决于数据传输协议如何处理丢失、损坏及延时过大的分组。解决流水线差错恢复有两种基本方法是:回退N步(Go-Back-N,GBN)和选择重传(Selective Repeat,SR)。

2. 回退N步

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

image

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

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

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

下图是GBN 协议发送方扩展 FSM 描述:
image

如上描述,GBN 协议发送方必须响应三种类型的事件:

  • 上层的调用。当上层调用 rdt_send() 时,发送方首先检查发送窗口是否已满,即是否有 N 个已发送但未被确认的分组。如果窗口未满,则产生一个分组并将其发送,并相应地更新变量。如果窗口已满,发送方只需将数据返回给上层,隐式地指示上层该窗口已满。然后上层可能会过一会儿再试。在实际实现中,发送方更可能缓存这些数据,或者使用同步机制(如一个信号量或标志)允许上层在仅当窗口不满时才调用 rdt_send()。
  • 收到一个ACK。在 GBN 协议中,对序号为 n 的分组的确认采取累积确认(cumulative acknowledgment)的方式,表明接收方已正确接收到序号为 n 的以前且包括 n 在内的所有分组。
  • 超时事件。协议的名字“回退 N 步”来源于出现丢失和时延过长分组时发送方的行为。就像在停等协议中那样,定时器将再次用于恢复数据或确认分组的丢失。如果出现超时,发送方重传所有已发送但未被确认过的分组。上图中发送方仅使用一个定时器,如果收到了一个 ACK,但仍有已发送但未被确认的分组,则定时器被重新启动。如果没有已发送但未被确认的分组,该定时器被终止。

下图是 GBN 协议接收方扩展 FSM 描述:

image

在 GBN 中,接收方的动作也很简单。如果一个序号为 n 的分组被正确接收到,并且按序(即上次交付给上层的数据是序号为 n - 1 的分组),则接收方为分组 n 发送一个 ACK,并将该分组中的数据部分交付到上层。在所有其他情况下,接收方将丢弃该分组,并为最近按序接收的分组重新发送 ACK。注意到因为一次交付给上层一个分组,如果分组 k 为已接受并交付,则所有序号比 k 小的分组也已经交付。因此,使用累积确认是 GBN 的一个自然的选择。

尽管丢弃一个正确接收(但失序)的分组。但这样做是有道理的。因为接收方必须将数据按序交付给上层,假设现在期望接收分组 n,而分组 n + 1 却到了,因为数据必须按序交付,所以接收方可能缓存分组 n + 1,然后,在它收到并交付分组 n 后,再将该分组交付到上层。但是,如果分组 n 丢失,则该分组及分组 n + 1 最终将在发送方根据 GBN 重传规则而被重传,所以,接收方只需要直接丢弃分组 n + 1 即可。这种方法的优点是接受缓存简单,即接收方不需要缓存任何失序分组。因此,虽然发送方必须维护窗口的上下边界及 nextseqnum 在该窗口中的位置,但是接收方需要维护的唯一信息就是下一个按序接收的分组的序号。该值保存在 expectedseqnum 变量中。当然,丢弃一个正确接收的分组的缺点是随后对该分组的重传也许会丢失或出错,因此甚至需要更多的重传。

一个示例如下:

image

3. 选择重传

顾名思义,选择重传(SR)协议通过让发送方仅重传那些它怀疑在接收方出错(即丢失或受损)的分组而避免了不必要的重传。这种个别的、按需的重传要求接收方逐个地确认正确接收的分组。再次用窗口长度 N 来限制流水线中未完成、未被确认的分组数。然而,与 GBN 不同的是,发送方已经收到了对窗口中某些分组的 ACK。

下图描述了发送方与接收方的序号空间:

image

SR 发送方的事件与动作:

  • 从上层收到数据。当从上层接收到数据后,SR 发送方检查下一个可用于该分组的序号。如果序号位于发送方的窗口内,则将数据打包并发送;否则就像在 GBN 中一样,要么将数据缓存,要么将其返回给上层以便以后传输。
  • 超时。定时器再次被用来防止丢失分组。然而,现在每个分组必须拥有其自己的逻辑定时器,因为超时发生后只能发送一个分组。可以使用单个硬件定时器模拟多个逻辑定时器的操作。
  • 收到ACK。如果收到 ACK,倘若该分组序号在窗口内,则 SR 发送方将那个被确认的分组标记为已接收。如果该分组的序号等于 send_base,则窗口基序号向前移动到具有最小序号的未确认分组处。如果窗口移动了并且有序号落在窗口内的未发送分组,则发送这些分组。

SR 接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存直到所有丢失分组(即序号更小的分组)皆被收到为止,这时才可以将一批分组按序交付给上层。

SR 接收方的事件与动作:

  • 序号在 [rcv_base, rcv_base+N-1] 内的分组被正确接收。在此情况下,收到的分组落在接收方的窗口内,一个选择 ACK 被回送给发送方。如果该分组以前没收到过,则缓存该分组。如果该分组的序号等于接收端的基序号(rcv_base),则该分组以及以前缓存的序号连续的(起始于 rcv_base 的)分组交付给上层。然后,接收窗口按向前移动分组的编号向上交付这些分组。
  • 序号在 [rcv_base-N, rcv_base-1] 内的分组被正确收到。在此情况下,必须产生一个 ACK,即使该分组是接收方以前确认过的分组。
  • 其他情况。忽略该分组。

注意上面的第二步,接收方需要重新确认(而不是忽略)已收到过的那些序号小于当前窗口基序号的分组。如果分组 send_base 的 ACK 没有从接收方传播回发送方,则发送方最终将重传分组 send_base,即使显然接收方已经收了该分组。如果接收方不确认该分组,则发送方窗口将永远不能向前滑动!

上面的例子说明了对于 SR 协议(和很多其他协议一样) 对于哪些分组已经被正确接收,哪些没有,发送方和接收方并不总能看到相同的结果。对 SR 协议而言,这就意味着发送方和接收方的窗口并不总是一致。

一个示例如下:

image

当我们面对有限序号范围的现实时,发送方和接收方窗口间缺乏同步会产生严重的后果。考虑下面的例子:

image

在这个例子中,有四个分组序号 0、1、2、3 且窗口长度为 3。假定发送了分组 0 至 2,并且接收方被正确接收且确认了。此时,接收方窗口落在 4、5、6 个分组上,其序号分别为 3、0、1.现在考虑两种情况。

在第一种情况下,如上图中的 a 图所示,对前 3 个分组的 ACK 丢失,因此发送方重传这些分组。因此,接收方下一步要接收序号为 0 的分组,即第一个发送分组的副本。

在第二种情况下,如上图中的 b 图所示,对前 3 个分组的 ACK 都被正确交付。因此发送方向前移动窗口并发送第 4、5、6 个分组,其序号分别为 3、0、1.序号为 3 的分组丢失,但序号为 0 的分组到达(一个包含新数据的分组)。

显然,接收方并不知道发送方那边出现了什么问题,对于接收方自己来说,上面两种情况是等价的。没有办法区分是第一个分组的重传还是第 5 个分组的初次传输。所以,窗口长度比序号空间小 1 时协议无法正常工作。但窗口应该有多小呢?

答案是:窗口长度必须小于或等于序号空间大小的一半。

4. 可靠数据传输过程中的分组重新排序问题

在前面的所有假设中,我们都是假定分组在发送方与接收方之间的信道中不能被重新排序。但是当连接两端的信道是一个网络时,分组重新排序是可能会发生的。

分组重新排序的一个表现就是一个具有序号或确认号 x 的分组的旧副本可能会出现,即使发送方或接收方的窗口中都包含 x。

对于分组重新排序,信道可被看成基本上是在缓存分组,并在将来任意时刻自然地释放出这些分组。由于序号可以被重新使用,那么必须小心,以免出现这样的冗余分组。

实际应用中采用的方法是:确保一个序号不被重新使用,直到发送方“确信”任何先前发送的序号为 x 的分组都不再在网络中为止。通过假定一个分组在网络中的“存活”时间不会超过某个固定最大时间量来做到这一点。在高速网络的 TCP 扩展中,最长的分组寿命被假定为大约 3 分钟 [RFC 1323]。

5. 可靠数据传输机制及其用途总结

机制 用途和说明
检验和 用于监测在一个传输分组中的比特错误
定时器 用于超时/重传一个分组,可能因为该分组(或其ACK)在信道中丢失了。由于当一个分组延时但未丢失,或当一个分组已被接收方接收但从接收方到发送方的 ACK 丢失时,可能产生超时事件,所以接收方可能会收到一个分组的多个冗余副本
序号 用于为从发送方流向接收方的数据分组按序号编号。所接受分组的序号的空隙可使接收方检测出丢失的分组。具有相同序号的分组可使接收方检测出一个分组的冗余副本
确认 接收方用于告诉发送方一个分组或一组分组已经被正确地接收到了。确认报文通常携带着被确认的分组或多个分组的序号。确认可以是逐个的或积累的,这取决于协议
否定确认 接收方用于告诉发送方某个分组未被正确的接收。否定确定报文通常携带着未被正确接收的分组的序号
窗口、流水线 发送方也许被限制仅发送那些序号落在一个指定范围内的分组。通过允许一次发送多个分组但未被确认,发送方的利用率可以在停等操作模式上得到增加。窗口长度可根据接收方接收和缓存报文的能力、网络中的拥塞程度或两者的情况来进行设置