滑动窗口
滑窗出现的原因
之前所有的通信方式都是这样,发送数据->等待ACK->发送数据->等待ACK,这种单线工作方式叫做停止等待(stop-and-wait
),停止等待虽然实现了TCP传输的可靠性,但是同时牺牲了网络通信的效率,在等待ACK的时间段内,我们的网络都处于闲置状态。
我们希望有一种方式,可以同时发送出多个片段。然而如果同时发出多个片段,那么由于IP包传送是无次序的,有可能会生成乱序片段,也就是后发出的片段先到达,在"停止等待"的工作方式下,乱序片段完全被拒绝,这也很不效率。毕竟,乱序片段只是提前到达的片段。我们可以在缓存中先存放它,等到它之前的片段补充完毕,再将它缀在后面。然而,如果一个乱序片段实在是太过提前,那这个流传输就太乱了。该片段将长时间占用缓存。
我们需要一种折中的方法来解决该问题:利用缓存保留一些"不那么乱"的片段,期望能在段时间内补充上之前的片段。所以计算机暂不处理,但发送相应的ACK
。对于乱得比较厉害的片段,无情的拒绝它们:不处理,也不发送对应的ACK
,此时滑窗就应运而生了。
滑窗是如何工作的
滑窗(sliding window
)同时应用于接收方和发送方,双方各有一个滑窗。每个滑窗中可以有多个片段,当片段位于滑窗中时,表示TCP
正在处理该片段。也就是可以同时处理多个片段。滑窗越大,同时处理的片段数目越多。当然,滑窗越大,计算机也必须分配出更多的缓存供滑窗使用。天下毕竟没有免费的午餐。
简单画了个图希望能够方便理解
发送方
片段从左向右排列,可以清楚的看到有三个部分
- 红色片段:已发送并且收到ACK确认的片段
- 白色片段:已发送暂未收到ACK确认的片段
- 绿色片段:未发送的片段
滑窗中的片段4、5、6
,已经发送出去,并等待相应的ACK
。如果收到片段4
的ACK
,滑窗将向右移动。这样,滑窗中将有新的片段7
。片段7
被发送出去,等待ACK
。然后,在接收到片段5的ACK之前,滑窗不会移动,即使已经收到了片段6
的ACK
也不会移动,这样,就保证了片段的的片段序列。
接收方
其实大体也很类似
片段确认ACK
从左向右排列
- 红色为已经成功接收并且发送ACK确认的片段
- 白色为等待接收的片段
片段1、2、3
已经接收并确认了,此时等待接收片段4、5、6
,如果此时接受到片段4
,滑窗则会向右一格,等待接收片段5、6、7
,如果片段5、6
在片段4
之前到的话,滑窗因为有空缺,不会移动,直至片段4
成功接收并确认,滑窗才会向右移动,如果出现滑窗外的片段,则会丢弃不会接收和确认
总结
TCP协议和UDP协议走了两个极端。TCP协议复杂但可靠,UDP协议轻便但不可靠。在处理异常的时候,TCP极端负责,而UDP一副无所谓的样子。在TCP中,分段和编号实现了次序。ACK和重新发送实现了可靠性。滑窗则让上面的机制更加有效率的运行。不放弃,这就是TCP协议的态度。