为什么要有滑动窗口?
首先,TCP是全双工协议,意味着会话双方可以同时接收和发送数据,其中会话双方都各自维护一个发送和接收窗口,各自的接收窗口取决于应用、系统、硬件的限制,发送窗口则要求取决于对端通告的接收窗口,要求两者相同。可以想象一下,如果发送端发送数据过快超过接收端的数据处理速率,这就意味着接收端会产生数据溢出的情况。为了避免这种情况,所以才出现滑动窗口来解决流量控制的问题。
滑动窗口的机制
- 发送窗口只有接收到发送窗口内字节的确认ACK,才会移动发送窗口的左边界;
- 接收窗口只有在前面所有的数据段都确认接收到的情况下,才会移动接收窗口的左边界,以此确保对端会对未收到的数据进行重传。
- 遵循快速重传,累计确认,选择确认等规则
TCP的四种拥塞控制算法
慢开始,拥塞控制,快重传,快恢复
拥塞控制的过程
在TCP双方建立逻辑链接关系时,发送端设置拥塞窗口cwnd=1,还设置了慢开始门限ssthresh。
在执行慢开始算法时,发送方每收到一个对新报文段的确认时,拥塞窗口cwnd+1,然后开始下一轮的传输(此时cwnd=2,发送方发送2个报文段,接收方回复2个ACK确认,然后cwnd=4,以此类推,这个过程是指数增长的),直到cwnd>=ssthresh时,开始改用拥塞避免算法。
使用拥塞避免算法时,每个传输轮次不再是指数增长的,拥塞窗口cwnd只能线性+1。(假设24个报文段中,发送方只收到20个确认ACK,意味着这个过程丢失了4个报文段,一段时间后这4个丢失报文段的超时重传计时器超时了,发送方会误认为网络发生阻塞(实际也可能是数据包在网络中丢失),然后更改了慢开始门限ssthresh和重置cwnd=1,并开始重新开始慢开始算法,导致传输效率降低)
为了避免这个误判,引入了快重传。快重传其实就是使发送方尽快进行重传,而不是等待超时计时器超时才重传,要求接收方要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认,发送方一旦收到3个连续的重复确认,则将相应的报文段立即重传,不必等待超时计时器超时。(对于个人丢失的报文段,发送方也不会出现超时重传,也不会误判网络阻塞)
快恢复,发送发一旦收到三个重复的确认,就知道现在只是丢失了个别报文段,于是不再使用慢开始算法,而是执行快恢复算法(发送方将慢开始门限ssthresh和拥塞窗口cwnd调整为当前窗口的一般,执行拥塞避免算法)
模拟流程:
- 发送方维护一个叫做拥塞窗口cwnd的状态变量,其值取决于网络的拥塞程度,并且动态变化;
- 发送方将拥塞窗口作为发送窗口,即swnd=cwnd
- 维护一个慢开始门限ssthresh状态变量
3.1 当cwnd<ssthresh时,使用慢开始算法
3.2 当cwnd=ssthresh时,既可以使用慢开始算法,也可以使用拥塞避免算法
3.3 当cwnd>ssthresh时,改用拥塞避免算法
为什么是三次确认ACK才进行快重传?
主要的考虑还是要区分包的丢失是由于链路故障还是乱序等其他因素引发。两次duplicated ACK时很可能是乱序造成的!三次duplicated ACK时很可能是丢包造成的!四次duplicated ACK更更更可能是丢包造成的!但是这样的响应策略太慢。丢包肯定会造成三次duplicated ACK!综上是选择收到三个重复确认时窗口减半效果最好,这是实践经验。
对比滑动窗口和拥塞窗口
滑动窗口是控制接收以及同步数据范围的,用于流量控制,在接收端使用,由于TCP是双全工,所以两边都有滑动窗口;
拥塞窗口是控制发送速率的,避免发的过多接收端处理不过来,在发送端使用。
其中,两个窗口的维护是独立的,滑动窗口主要由接收端反馈缓存情况来维护,而拥塞 窗口主要由发送方根据拥塞控制算法检测网络拥塞情况程度来决定的。