Sliding Window
滑动窗口协议是这样一个模型:
- 发送方有发送窗口 $W_T$,限制连续发送但尚未确认的数据数量。
- 接收方有接收窗口 $W_R$,限制当前愿意接收的数据序号范围。
- ACK 推动发送窗口向前滑动。
- 按序收到数据推动接收窗口向前滑动。
- 序号字段有限,窗口大小必须避免新旧数据混淆。
停止-等待、GBN、SR 都是这个模型的不同参数取值:
| 协议形态 | $W_T$ | $W_R$ | 失序数据处理 |
|---|---|---|---|
| 停止-等待 | $1$ | $1$ | 不形成流水线 |
| GBN | $>1$ | $1$ | 不接收失序数据,直接丢弃 |
| SR | $>1$ | $>1$ | 接收并缓存窗口内失序数据 |
GBN 和 SR 的共同基础是滑动窗口。区别主要来自 $W_R$:接收窗口为 $1$ 时只能按序收;接收窗口大于 $1$ 时可以先缓存失序数据。
发送窗口
发送窗口 $W_T$ 表示发送方最多允许多少个“已发送但尚未确认”的数据在路上。
窗口内的数据分为两类:
- 已发送但未确认:保留在发送缓存中,超时后可重传。
- 尚未发送但允许发送:可以立即发送。
收到 ACK 后,发送方把已经确认的数据移出窗口,窗口右边进入新的序号。窗口满时,发送方即使还有数据,也不能继续发送。
接收窗口
接收窗口 $W_R$ 表示接收方当前愿意接受哪些序号。
若 $W_R=1$,接收方只接受当前期待的最小序号。其他序号即使正确到达,也被当作失序数据丢弃。
若 $W_R>1$,接收方可以接受窗口范围内的失序数据,先放入接收缓存,等缺口补齐后再按序交付。
接收窗口左边界只在当前期待的最小序号已经按序收到时移动。即使后面的数据已经缓存,只要最小缺口没补齐,接收窗口也不能越过这个缺口。
序号空间约束
若序号字段为 $n$ bit,则序号空间大小为:
$$
2^n
$$
序号会循环使用。例如 $n=2$ 时,序号只有 $0,1,2,3$,发送到 $3$ 后又回到 $0$。
统一约束是:
$$
W_T+W_R\le 2^n
$$
这个式子是滑动窗口协议的核心。它保证发送方可能重传的旧数据,和接收方愿意接收的新数据,不会在同一个循环序号上重叠。
[!proof]
设序号空间大小为:$$
N=2^n
$$设发送方从序号 $a$ 开始发送,发送窗口大小为 $W_T$。在最坏情况下,发送方已经连续发出了:
$$
a,a+1,\dots,a+W_T-1
$$这些序号都按模 $N$ 循环计算。若这些数据已经被接收方正确收到,但 ACK 全部丢失,那么接收方会认为这些旧数据已经完成接收,接收窗口向前移动到:
$$
a+W_T
$$于是接收方现在愿意接收的新序号范围是:
$$
a+W_T,\ a+W_T+1,\ \dots,\ a+W_T+W_R-1
$$与此同时,发送方没有收到 ACK,仍然认为最初那 $W_T$ 个数据没有确认,因此它仍可能重传旧序号:
$$
a,\ a+1,\ \dots,\ a+W_T-1
$$因此,为了避免混淆发送方可能重传的旧序号集合,必须和接收方当前愿意接收的新序号集合不相交。两个集合在大小为 $N$ 的循环序号空间中首尾相接:
$$
\underbrace{W_T}{旧数据可能重传}
+\underbrace{W_R}{新数据允许接收}
\le N
$$代回 $N=2^n$,得到:
$$
W_T+W_R\le 2^n
$$
若 $W_T+W_R>2^n$,这两个区间必然在循环序号空间中重叠。重叠处的某个序号既可能是发送方重传的旧数据,又可能是接收方窗口内允许接收的新数据。接收方只看序号时无法区分二者,滑动窗口协议就会把旧数据误收为新数据。
常见结论都来自这个式子:
| 协议形态 | 代入约束 | 结果 |
|---|---|---|
| 停止-等待 | $W_T=1,W_R=1$ | 至少需要 2 个序号,1 bit 足够 |
| GBN | $W_R=1$ | $W_T\le 2^n-1$ |
| SR | 常取 $W_T=W_R$ | $W_T=W_R\le 2^{n-1}$ |
窗口如何滑动
发送方窗口滑动:
- 发送方连续发送窗口内允许发送的数据。
- 已发送但未确认的数据保留在发送缓存中。
- ACK 到达后,确认的数据从发送缓存中删除。
- 若窗口左端数据已确认,发送窗口向右滑动。
接收方窗口滑动:
- 到达数据的序号落在接收窗口内,且没有检测出误码,接收方才考虑接收。
- 若数据正好是当前期待的最小序号,接收方可按序接收。
- 若 $W_R>1$,窗口内失序数据可以先缓存。
- 当前最小缺口补齐后,接收方按序交付,并把接收窗口向右滑动。
丢失一个数据时发生什么
设发送方窗口允许连续发送 0,1,2,3,其中 1 丢失或出错。
若 $W_R=1$:
- 接收方收到
0后确认0,窗口期待1。 1丢失或出错。2、3到达时不是当前期待序号,被丢弃。- 发送方从
1开始回退重传。
若 $W_R>1$:
- 接收方收到
0后确认0,窗口期待1。 1丢失或出错。2、3仍落在接收窗口内,接收方先缓存并分别确认。- 发送方只需要重传
1。 1到达后,接收方把1,2,3按序交付。
二者差异:
- $W_R=1$:失序数据不能进入接收窗口,只能丢弃,所以会回退重传。
- $W_R>1$:窗口内失序数据可以缓存,所以可以选择重传缺失项。
ACK 的含义
ACK 可以有两种常见含义。
累积确认:ACK k 表示 k 及其之前的数据都已经按序正确收到。它实现简单,确认报文少,即使某个 ACK 丢失,也可能被后面的 ACK 覆盖。
逐个确认:每个正确收到的数据单独确认。它能告诉发送方哪些数据已经到达,哪些还缺失。
确认方式由接收窗口行为决定。若接收方不缓存失序数据,累积确认就够用;若接收方缓存失序数据,发送方必须知道缓存中已经有哪些数据。
信道利用率
信道利用率关心的是:信道有多少时间真正用于发送有效数据。
停止-等待的利用率
停止-等待协议中,发送方发完一个数据后必须等待 ACK 返回。设:
- $T_D$:发送一个数据分组的发送时延。
- $T_A$:发送一个 ACK 的发送时延。
- $RTT$:数据从发送方到接收方,再让 ACK 返回发送方的往返传播时间。
发送方完成一轮“发送数据并等到 ACK”需要:
$$
T_D+RTT+T_A
$$
这一轮中,真正用于发送数据的时间只有 $T_D$,所以:
$$
U_{\text{stop}}=\frac{T_D}{T_D+RTT+T_A}
$$
ACK 通常很短,可近似忽略 $T_A$:
$$
U_{\text{stop}}\approx\frac{T_D}{T_D+RTT}
$$
当 $RTT$ 远大于 $T_D$ 时,发送方大部分时间都在等待,信道利用率很低。
多帧滑动窗口的利用率
若发送窗口大小为 $W_T$,在没有差错、接收方处理能力足够的情况下,发送方最多可以连续发送 $W_T$ 个数据分组。
连续发送这一批数据需要:
$$
W_T\cdot T_D
$$
若这一段连续发送时间仍小于等待 ACK 所需的周期,发送方发完窗口内数据后还会等待:
$$
W_T\cdot T_D<T_D+RTT+T_A
$$
若这一段连续发送时间已经覆盖等待 ACK 的周期,发送方刚发完一批,前面的 ACK 已经回来,窗口可以继续滑动,理想情况下信道可以持续被填满。
因此近似有:
$$
U_{\text{window}}\approx
\min\left(1,\frac{W_T\cdot T_D}{T_D+RTT+T_A}\right)
$$
若忽略 ACK 发送时延:
$$
U_{\text{window}}\approx
\min\left(1,\frac{W_T\cdot T_D}{T_D+RTT}\right)
$$
窗口多大才够
要让信道尽量不空闲,需要:
$$
W_T\cdot T_D\ge T_D+RTT+T_A
$$
忽略 ACK 发送时延时:
$$
W_T\ge 1+\frac{RTT}{T_D}
$$
这个式子说明:传播等待越长,或者单个数据发送越快,就需要越大的窗口才能把信道填满。
例如,若 $RTT=9T_D$,则:
$$
W_T\ge 1+\frac{9T_D}{T_D}=10
$$
窗口小于 $10$ 时,发送方发完窗口内数据后仍要等待 ACK;窗口达到 $10$ 后,理想情况下才能连续发送。
窗口不是越大越好
扩大窗口可以提高理想情况下的信道利用率,但窗口受多个因素限制:
- 接收方缓存有限,窗口过大会造成接收压力。
- 序号空间有限,必须满足 $W_T+W_R\le 2^n$。
- 未确认数据越多,发送方缓存压力越大。
- 发生丢失或误码时,窗口越大,可能牵涉的重传和缓存管理越重。
因此,窗口大小是在信道利用率、接收能力、序号空间和重传代价之间折中。