流水线可靠数据传输协议
一、 停止等待 (stop-and-wait) 协议的低带宽利用率
举一个例子来说明。假设两个主机分布在美国东西海岸,他们之间的光速传播往返时延 RTT 大约是30毫秒。这两个主机通过一条发送速率(即带宽)是 1Gbps 的信道相连。数据的分组长 L 是 1000 字节,发送一个分组进入信道的时间是:
\[ t_{trans} = \frac{L}{R} = \frac{8000bit/pkt}{10^9bit/s} = 8\mu s/pkt\]
如果发送方在 \(t=0\) 时刻开始发送分组,则在 \(8\mu s\) 后,最后1bit进入了发送端信道。经过 \(15ms\) 后,分组的第一个 bit 到达接收端;在 \(15.008ms\) 时刻,分组的最后一个 bit 到达接收端。假设接收端的 ACK 产生和发送不占用时间,则再经过 \(15ms\) 以后,即 \(t=30.008ms\),发送端接收到接收端的ACK,发送端可以发送下一个分组。
在 \(30.008ms\) 内,发送方的发送使用了 \(0.008ms\)。我们定义信道利用率为:发送方实际忙于发送比特到信道的时间与发送时间之比,则停止等待协议的发送方利用率为:
\[U_{sender} = \frac{L/R}{RTT+L/R} = \frac{0.008}{30.008} = 0.00027\]
这是一个网络协议限制底层网络硬件所提供的能力的例子。
二、流水线传输协议
解决上述问题的一个方法是:不适用停止等待方式,运行发送方发送多个分组而无需等待确认。由于许多从发送方向接收方输送的分组可以被看成是填充到一条流水线中,因此这种技术被称为流水线 (pipelining)。当然,流水线会增加协议的复杂度:
- 必须增加序号范围
因为信道中的分组要有一个唯一的序号,会有多个分组在信道中未被确认。 - 协议的发送方和接收方必须缓存多个分组
发送方至少应该缓存已经发送却还没有被确认的分组。接受方也许应该缓存已经正确接收的分组。 - 所需的序号范围和对缓存大小的要求取决于协议如何处理丢失、损坏及延时大的分组
解决流水线差错错误的两种基本思路:回退N步和选择重传。
2.1 回退N步 (Go-Back-N)
主要特点是如果接收方丢弃所有失序分组。
我们先来看下回退N部协议的基本原理。
对于发送方来说,每个分组都有一个序号。在每一个时刻,发送方维护几个变量:
- 基序号 (base)
最早的未确认分组的序号。 - 下一个序号 (nextseqnum)
最小的未使用序号,也是下一个待发送分组的序号。 - 窗口长度 (window size) N
根据这三个变量,将序号范围分隔为4段:
- [0, base-1]
已经发送并被确认的分组。 - [base, nextseqnum -1]
已经发送但未被确认的分组。 - [nextseqnum, base + N -1]
要立即被发送的分组。 大于等于 base + N
不能使用的,直至当前流水线中未被确认的分组已得到确认为止。
已经被发送但还未被确认的分组的许可序号范围可以被看成是一个序号范围长度为N的窗口。随着协议的运行,该窗口在序号空间向前滑动。因此 GBN 协议被称为滑动窗口协议 (silding-window protocol)。有长度N的限制是为了进行流量控制。
基于 ACK、无 NAK 的 GBN 协议的发送方 FSM 如下: 
GBN 发送方相应三种类型的事件:
- 上层调用
即上层调用rdt_send()
。如果窗口未满,则产生一个分组,并将其发送,并更新状态。否则把数据返回上层,告知其窗口已满。 - 收到一个ACK
GBN 协议采用累积确认 (cumulative acknowledgement) 的方式,即收到序号 \(n\) 的ACK, 表明接收方已经收到序号 \(n\) 及之前的所有分组。
如果收到一个ACK,但仍有未被确认的分组,则重启定时器。
如果没有已发送但未被确认的分组,终止定时器。 - 定时器超时
发送方将重传所有已发送但未被确认的分组。发送方仅使用一个定时器,可被当做最早的已发送但未被确认的分组所使用的定时器。
GBN 接收方的 FSM 如下:

接收方的响应很简单。如果一个序号为 \(n\)的分组被正确接收到,并且按序(上一个接收到的分组是序号 \(n-1\)),则发送一个序号为 \(n\) 的ACK给发送方,并把该分组交付上层。其他情况下都是丢弃接收到的分组,并为最近按序接收的分组重新发送 ACK。
GBN协议的优缺点
- 优点
接收缓存简单,即接收方不需要缓存任何失序分组。接收方需要维护的唯一信息就是下一个按序接收的分组的序号,即 FSM 中的expectedseqnum
变量。 - 缺点
会丢弃已经正确接收的分组。对该分组的重传也许会丢失或出错,因此甚至需要更多的重传。也会加大对整个网络的压力。
当带宽时延积很大时,单个分组的差错就能引起 GBN 重传大量分组,而许多分组根本没有必要重传。随着信道差错率的增加,信道可能会被这些没有必要重传的分组充斥。
2.2 选择重传 (Selective Repeat, SR)
选择重传协议让发送方仅重传那些它怀疑在接收方出错的分组,避免了不需要的重传。
SR 发送方
下图显示了 SR 发送方看到的序号空间。

如上图所示,发送方已经收到了窗口中某些分组的 ACK。窗口长度 N 仍被用来限制流水线中未完成、未被确认的分组数量。
SR 发送方采取的动作如下:
- 从上层收到数据
发送方检查下一个可用于该分组的序号。如果序号在发送方窗口内,则发送该分组,否则将其返回上层或缓存以便以后传输。 - 超时
每个分组都必须拥有自己的逻辑定时器,定时器用来防止丢失分组。
可以用单个硬件定时器模拟多个逻辑定时器操作。 - 收到 ACK
如果收到 ACK 的分组序号在窗口内,则发送方将那个被确认的分组标记为已接受。
如果分组序号为 send_base,则窗口基序号向前移动到具有最小序号的未确认分组处。
如果窗口移动了并且有序号落在窗口的未发送分组,则发送这些分组。
SR 接收方
接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存直到所有丢失分组(即序号更小的分组)皆被收到为止。此时把这一批分组按序交付给上层。
- 序号在 [rcv_base, rcv_base + N -1] 内的分组被正确接收
即收到的分组落在接收方窗口内,一个 ACK 被回送到发送方。
如果该分组没有收到过,则缓存该分组。
如果该分组的序号等于接收窗口的基序号 (rcv_base),则将该分组以及之前缓存的序号连续的分组交付给上层,然后接收窗口向前移动。 - 序号在 [rcv_base -N, rcv_base -1] 内的分组被正确收到
必须产生一个 ACK, 即使该分组是接收方已经确认过的分组。 - 其他情况
忽略分组
值得注意的是,在第 2 种情况下,接收方重新确认已收到过的那些序号小于当前窗口基序号的分组。这种重新确认是有必要的,因为 ACK 可能会丢失或损坏。
比如分组 send_base
的 ACK 没有从接收方传播会发送方,那么发送方会重传分组 send_base
。如果接收方不确认该分组,则发送方窗口将永远不能向前滑动!
对于 SR 协议来说,发送方和接收方的窗口并不总是一致。
三、 其他一些事情
- TCP 使用的是 GBN 协议和 SR 协议的混合体
- 窗口长度必须小于等于序号空间大小的一半
- 分组可能被重新排序
由于两台主机不是直接连接的,不同分组经过的路由不同,而且路由器可能会复制多份分组。因此分组在发送方和接收方之间的信道可能被重新排序。
一个表现就是一个具有序号或区分号 \(x\) 的分组的旧副本可能重新出现,即使发送方或接收方的窗口中都没有包含 \(x\)。
实际中为了避免出现这种冗余分组,采取的措施是:确保一个序号不被重新使用,直到发送方“确信”任何先前发送的序号为 \(x\) 的分组都不再出现在网络中。通过假定一个分组在网络中的“存活”时间不会超过某个固定最大时间量,对于 TCP 来说,这个值被假定为 3 分钟。
四、来源
- Kurose, KeithW.Ross, 库罗斯,等. 计算机网络:自顶向下方法[M]. 高等教育出版社, 2009.