文章目录
滑动窗口
窗口的本质: 窗口实际上是操作系统开辟的一个缓存空间
,用来缓存数据的。
为什么要缓存数据?——节约性能开销
- 批量收发
数据放在缓存空间中攒起来批量发送和批量接收
- 重传数据
发送方在收到确认应答ACK之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。如果没有收到则重传数据
滑动窗口
滑动窗口的意思就是窗口大小不固定,是滑动变化的。
为什么?
发送方不能随心所欲的发送报文,还得考虑接收方的处理能力
。
当接收方硬件不如发送方,或者系统繁忙、资源紧张时,是无法瞬间处理这么多报文的。于是报文只能被丢掉,使得网络效率非常低。
为了解决这种现象发生,TCP 提供一种机制:可以让「发送方」根据「接收方」
的实际接收能力
控制发送的数据量
,这就是滑动窗口
的由来。
发送窗口
发送滑动窗口大小由接收窗口决定,主要分为下面四个部分
接收窗口
接收窗口主要分为三个部分:
接收窗口和发送窗口的大小是相等的吗?
并不是完全相等,接收窗口的大小是约等于
发送窗口的大小的。
因为滑动窗口并不是一成不变的。比如,当接收方的应用进程读取数据的速度非常快的话,接收窗口就会变大。新的接收窗口大小通过 TCP 报文中的 Windows
字段告诉发送方。但是这个传输过程是存在时延
的,所以接收窗口和发送窗口是约等于
的关系。
流量控制
为什么需要流量控制?
流量控制的目的是避免发送方数据发的太快导致接收方处理不过来、
因此TCP 提供一种机制可以让「发送方」根据「接收方」的实际接收能力控制发送的数据量,这就是流量控制
。
窗口关闭和死锁
窗口关闭
如果接收方太忙了,来不及取走接收窗口里的数据,那么就会导致发送方的发送窗口越来越小。当窗口大小为 0
时窗口关闭 。
死锁
当发送窗口关闭后,接收方处理完数据后,会向发送方通告一个窗口非 0
的 ACK 报文重新开启窗口,如果这个通告窗口的 ACK 报文在网络中丢失了,此时发送方不敢发,接受方等着接收,互相等待。就会造成死锁,
怎么解决死锁
为了解决这个问题,TCP 为每个连接设有一个持续定时器
,只要 TCP 连接一方收到对方的零窗口通知
,就启动持续计时器
。
如果持续计时器超时还没收到接收方的非0窗口大小报文,就会发送窗口探测报文
,而对方在确认这个探测报文时,给出自己现在的接收窗口大小。如下图所示:
窗口探查探测的次数一般为 3 次。如果 3 次过后接收窗口还是 0 的话,有的 TCP 实现就会发 RST 报文来重置连接
。
糊涂窗口综合症(发送小报文)
如果接收方太忙了,来不及取走接收窗口里的数据,那么就会导致发送方的发送窗口越来越小。
到最后,如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,要知道 TCP + IP 头
就有 40 个字节,为了传输那几个字节的数据,要搭上这么大的开销,这太不经济了。这就是糊涂窗口综合症。
怎么避免发送小报文?
接收方采用延迟确认
拥塞控制
流量控制和拥塞控制的区别?
流量控制的目的是避免发送方数据发的太快导致接收方处理不过来——堵在接收方
拥塞控制的目的就是避免「发送方」的数据填满整个网络——堵在网络中
怎么做到?
为了在「发送方」调节所要发送数据的量,定义了一个叫做拥塞窗口
的概念。
什么是拥塞窗口?
拥塞窗口 cwnd
是发送方维护的一个状态变量
,它会根据网络的拥塞程度动态变化
我们在前面提到过发送窗口 swnd
和接收窗口 rwnd
是约等于
的关系,
现在引入了拥塞窗口的概念后,swnd = min(cwnd, rwnd)
,发送窗口=min(拥塞窗口,接收窗口)
拥塞控制算法
拥塞控制算法包括下面四个阶段:
- 慢启动
- 拥塞避免
- 拥塞恢复算法
- 快速恢复
慢启动和拥塞避免
有一个叫慢启动门限 ssthresh
(slow start threshold)的状态变量。
- 当 cwnd < ssthresh 时,使用
慢启动算法
。 - 当 cwnd >= ssthresh 时,就会使用「
拥塞避免算法
」。
慢启动的算法规则:指数增长,1,2,4,8…
慢开始算法不是增长很慢,只是初始值比较小,因为一开始不知道网络情况,所以不能一上来就往网络中发很多很大的数据,从小数据开始,快速增长。
拥塞避免算法就是将原本慢启动算法的指数增长变成了线性增长,还是增长阶段,只是增长速度缓慢了一些。
就这么一直增长着后,网络就会慢慢进入了拥塞
的状况了,于是就会出现丢包
现象,这时就需要对丢失的数据包进行重传。
拥塞恢复算法——超时重传
当发生了「超时重传」
,则就会使用拥塞恢复算法
。
这个时候,sshresh 和 cwnd 的值会发生变化:
- ssthresh = cwnd/2,
- cwnd =
1
- 接着就重新开始
慢启动
快恢复——快速重传
当发生了「快速重传」
,则就会使用快速恢复算法
。
TCP 认为快速重传
这种情况不严重,因为大部分没丢,只丢了一小部分,所以不会将cwnd减小到1这么小。而是将cwnd 和ssthresh都设置为cwnd的一半,并执行拥塞避免算法,如下:
- cwnd = cwnd/2
- ssthresh =
cwnd
; - 接着执行
拥塞避免算法
线性增长
总结
初始使用慢启动指数增长,超过ssthresh之后开始拥塞避免,线性增长
超时重传之后触发拥塞恢复算法,threshold=cwnd/2,cwnd=1,然后慢启动指数增长
快速重传之后触发快恢复,cwnd = cwnd/2,ssthresh = cwnd;然后执行拥塞避免算法
线性增长