1、什么是TCP 糊涂窗口综合症?
TCP 报文首部就占 20 字节了,如果每次接收方只允许发送方发送两三个字节,那就为了传输这么几个有效的字节,还得附加上 20 字节的数据,这就是很浪费资源性能的
。 这就是所谓的“TCP 糊涂窗口综合症”。
所以 TCP 糊涂窗口综合症(Silly Window Syndrome, SWS)简单来说,其实就是接收方接收能力变差,窗口变小,导致发送方犯傻,其发送的数据只有一个大大的头部,真正携带的数据很少。
2、如何解决TCP 糊涂窗口综合症?
从接收方维度解决
接收方的策略很简单,目的就是防止发送方发送小数据嘛
- 那只要窗口大小 < 某个值(内核缓冲区大小的一半,也称为 最大段长度 MSS)的时候,就直接将窗口大小设置为 0,防止发送方发送小数据(
注意这里区分下内核缓冲区(buffer)和 CPU 缓存(cache)的概念
窗口的大小的本质是内核缓冲区的大小) - •然后等到窗口大小 >= 内核缓冲区大小的一半 的时候,才打开窗口,通告发送方,告知其可以发送数据。
这样就阻止了发送方发送小报文了。
还有一种方法,称为 “延迟确认应答”
我们知道接收方窗口大小的变化过程是下面这样的
-
接收方根据缓冲区空闲的空间大小,计算出后续能够接收多少字节的报文(即接收窗口的大小)
-
当内核接收到报文时,将其存放在缓冲区中,这样缓冲区中空闲的空间就变小了,接收窗口也就随之变小了
-
当进程调用
read
函数后(将数据从内核缓冲区复制到用户/进程缓冲区),报文数据被读入了用户空间,内核缓冲区就被清空,这意味着主机可以接收更多的报文,接收窗口就会变大
如果接受数据的主机在接收到报文的时候(第二步)就立刻返回 ACK 应答,这时候返回的窗口可能比较小。为什么这么说呢,举个例子:
-
假设接受方主机的内核缓冲区大小为 1M,一次性收到了 500K 的数据,如果在第二步就立刻回复应答,那么返回的窗口大小就是 500K
-
但实际上可能第三步处理得速度很快,很快就把 500K 数据从缓冲区消费掉了
-
所以,如果接收方稍微等一会再应答,那么这个时候返回的窗口大小就是 1M,这样,发送方能够发送的数据是不是更多了呢~ ,这就是延迟确认应答。
这表示当一个报文段到达时并不立即发送确认。接收端在确认收到的报文段之前一直等待,直到入缓存有足够的空间为止。延迟的确认防止了发送端的TCP滑动其窗口。当发送端的TCP发送完其数据后,它就停下来了。这样就防止了这种症状。迟延的确认还有另一个优点:它减少了通信量。接收端不需要确认每一个报文段。但它也有一个缺点,就是迟延的确认有可能迫使发送端重传其未被确认的报文段。可以用协议来平衡这个优点和缺点,例如定义了确认的延迟不能超过500毫秒
也确实没有必要对每一个数据段都进行确认应答,毕竟用的滑动窗口(累计应答),应答少一些也无妨。在 TCP 文件传输中,绝大多数都是每两个报文段返回一次确认应答:
从发送方维度解决
发送方的目的也很简单,就是不要犯傻去发送小报文就行了
常用的策略是 Nagle 算法
该算法是指发送端即使还有应该发送的数据,但如果这部分数据很少的话,则进行延迟发送的一种处理机制。
具体来说,就是仅在下列任意一种条件下才能发送数据
-
已发送的数据都已经收到确认应答时
-
可以发送的数据大小 >= MSS(最大报文长度)
如果两个条件都不满足,那么发送方就是囤积数据,等待一段时间后再进行数据发送。