糊涂窗口综合症和Nagle算法

前记:TCP/IP详解系列,毕竟不是一本教材,很多地方讲的不细致。比如SWS未说明是什么就开始介绍其避免方法,还和nagle扯在了一起,直觉告诉我二者一定有猫腻,边搜索一下,果然很有收获。今天贴在这里,分享给大家。

第一部分:SWS
何谓糊涂窗口综合症
  当发送端应用进程产生数据很慢、或接收端应用进程处理接收缓冲区数据很慢,或二者兼而有之;就会使应用进程间传送的报文段很小,特别是有效载荷很小。 极端情况下,有效载荷可能只有1个字节;而传输开销有40字节(20字节的IP头+20字节的TCP头) 这种现象就叫糊涂窗口综合症。
发送端引起的SWS
  如果发送端为产生数据很慢的应用程序服务(典型的有telnet应用),例如,一次产生一个字节。这个应用程序一次将一个字节的数据写入发送端的TCP的缓存。如果发送端的TCP没有特定的指令,它就产生只包括一个字节数据的报文段。结果有很多41字节的IP数据报就在互连网中传来传去。解决的方法是防止发送端的TCP逐个字节地发送数据。必须强迫发送端的TCP收集数据,然后用一个更大的数据块来发送。发送端的TCP要等待多长时间呢?如果它等待过长,它就会使整个的过程产生较长的时延。如果它的等待时间不够长,它就可能发送较小的报文段,于是,Nagle找到了一个很好的解决方法,发明了Nagle算法。而他选择的等待时间是一个RTT,即下个ACK来到时。
接收端引起的SWS
  接收端的TCP可能产生糊涂窗口综合症,如果它为消耗数据很慢的应用程序服务,例如,一次消耗一个字节。假定发送应用程序产生了1000字节的数据块,但接收应用程序每次只吸收1字节的数据。再假定接收端的TCP的输入缓存为4000字节。发送端先发送第一个4000字节的数据。接收端将它存储在其缓存中。现在缓存满了。它通知窗口大小为零,这表示发送端必须停止发送数据。接收应用程序从接收端的TCP的输入缓存中读取第一个字节的数据。在入缓存中现在有了1字节的空间。接收端的TCP宣布其窗口大小为1字节,这表示正渴望等待发送数据的发送端的TCP会把这个宣布当作一个好消息,并发送只包括一个字节数据的报文段。这样的过程一直继续下去。一个字节的数据被消耗掉,然后发送只包含一个字节数据的报文段。
  对于这种糊涂窗口综合症,即应用程序消耗数据比到达的慢,有两种建议的解决方法:
  1) Clark解决方法 Clark解决方法是只要有数据到达就发送确认,但宣布的窗口大小为零,直到或者缓存空间已能放入具有最大长度的报文段,或者缓存空间的一半已经空了。
  2 )延迟确认 第二个解决方法是延迟一段时间后再发送确认。这表示当一个报文段到达时并不立即发送确认。接收端在确认收到的报文段之前一直等待,直到入缓存有足够的空间为止。延迟的确认防止了发送端的TCP滑动其窗口。当发送端的TCP发送完其数据后,它就停下来了。这样就防止了这种症状。迟延的确认还有另一个优点:它减少了通信量。接收端不需要确认每一个报文段。但它也有一个缺点,就是迟延的确认有可能迫使发送端重传其未被确认的报文段。可以用协议来平衡这个优点和缺点,例如现在定义了确认的延迟不能超过500毫秒。

第二部分:Nagle算法
TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。
Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段。 所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。
Nagle算法的规则(可参考tcp_output.c文件里tcp_nagle_check函数注释):
(1)如果包长度达到MSS,则允许发送;
(2)如果该包含有FIN,则允许发送;
(3)设置了TCP_NODELAY选项,则允许发送;
(4)未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
(5)上述条件都未满足,但发生了超时(一般为200ms),则立即发送。
Nagle算法只允许一个未被ACK的包存在于网络,它并不管包的大小,因此它事实上就是一个扩展的停-等协议,只不过它是基于包停-等的,而不是基于字节停-等的。Nagle算法完全由TCP协议的ACK机制决定,这会带来一些问题,比如如果对端ACK回复很快的话,Nagle事实上不会拼接太多的数据包,虽然避免了网络拥塞,网络总体的利用率依然很低。另外,他是一个自适应的方法,读者可以自己按上述规则试验一下。
Nagle算法是silly window syndrome(SWS)预防算法的一个半集。SWS算法预防发送少量的数据,Nagle算法是其在发送方的实现,而接收方要做的时不要通告缓冲空间的很小增长,不通知小窗口,除非缓冲区空间有显著的增长。这里显著的增长定义为完全大小的段(MSS)或增长到大于最大窗口的一半。

注意:BSD的实现是允许在空闲链接上发送大的写操作剩下的最后的小段,也就是说,当超过1个MSS数据发送时,内核先依次发送完n个MSS的数据包,然后再发送尾部的小数据包,其间不再延时等待。(假设网络不阻塞且接收窗口足够大)
TCP_NODELAY 选项
默认情况下,发送数据采用Negale 算法。这样虽然提高了网络吞吐量,但是实时性却降低了,在一些交互性很强的应用程序来说是不允许的,使用TCP_NODELAY选项可以禁止Negale 算法。
此时,应用程序向内核递交的每个数据包都会立即发送出去。需要注意的是,虽然禁止了Negale 算法,但网络的传输仍然受到TCP确认延迟机制的影响。

TCP_CORK 选项
所谓的CORK就是塞子的意思,形象地理解就是用CORK将连接塞住,使得数据先不发出去,等到拔去塞子后再发出去。设置该选项后,内核会尽力把小数据包拼接成一个大的数据包(一个MTU)再发送出去,当然若一定时间后(一般为200ms,该值尚待确认),内核仍然没有组合成一个MTU时也必须发送现有的数据(不可能让数据一直等待吧)。
然而,TCP_CORK的实现可能并不像你想象的那么完美,CORK并不会将连接完全塞住。内核其实并不知道应用层到底什么时候会发送第二批数据用于和第一批数据拼接以达到MTU的大小,因此内核会给出一个时间限制,在该时间内没有拼接成一个大包(努力接近MTU)的话,内核就会无条件发送。也就是说若应用层程序发送小包数据的间隔不够短时,TCP_CORK就没有一点作用,反而失去了数据的实时性(每个小包数据都会延时一定时间再发送)。

Nagle算法与CORK算法区别

  Nagle算法和CORK算法非常类似,但是它们的着眼点不一样,Nagle算法主要避免网络因为太多的小包(协议头的比例非常之大)而拥塞,而CORK算法则是为了提高网络的利用率,使得总体上协议头占用的比例尽可能的小。如此看来这二者在避免发送小包上是一致的,在用户控制的层面上,Nagle算法完全不受用户socket的控制,你只能简单的设置TCP_NODELAY而禁用它,CORK算法同样也是通过设置或者清除TCP_CORK使能或者禁用之,然而Nagle算法关心的是网络拥塞问题,只要所有的ACK回来则发包,而CORK算法却可以关心内容,在前后数据包发送间隔很短的前提下(很重要,否则内核会帮你将分散的包发出),即使你是分散发送多个小数据包,你也可以通过使能CORK算法将这些内容拼接在一个包内,如果此时用Nagle算法的话,则可能做不到这一点。

时间: 2024-09-16 18:50:35

糊涂窗口综合症和Nagle算法的相关文章

【转载】糊涂窗口综合症和Nagle算法

第一部分:SWS 何谓糊涂窗口综合症 当发送端应用进程产生数据很慢.或接收端应用进程处理接收缓冲区数据很慢,或二者兼而有之,就会使应用进程间传送的报文段很小,特别是有效载荷很小. 极端情况下,有效载荷可能只有 1 个字节:而传输开销有40 字节(20 字节的 IP 头 + 20 字节的 TCP 头) 这种现象就叫糊涂窗口综合症. 发送端引起的SWS 发送端的 TCP 可能产生糊涂窗口综合症,如果发送端为产生数据很慢的应用程序服务(典型的有 telnet 应用).例如,一次产生一个字节.这个应用程

计算机网络-nagle算法疑问 tcp/ip nagle 网络

问题描述 nagle算法疑问 tcp/ip nagle 网络 最近在学习tcp/ip,在拥塞控制部分出现了nagle算法,网上看了一些资料http://b.baidu.com/view/2468335.htm Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段. 所谓"小段",指的是小于MSS尺寸的数据块,所谓"未被确认",是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到. Nagle算法的规则(可参考tcp_output.c文件里t

nagle算法-tcpip详解卷一关于图19-4的疑问

问题描述 tcpip详解卷一关于图19-4的疑问 Nagle算法是讲 一个新的小报文要发送,必须等前一个小报文的ack收到之后才能发送: 在卷1的P204页图19-4讲解Nagle算法时,举的例子 图中报文14的ack还没有收到,报文15就发送出去了,感觉是违背了Nagle算法,书中还专门这对这个做了解释说没有违背Nagle算法: 报文段 14和15看起来似乎是与 Nagle算法相违背的,但我们需要通过检查序号来观察其中 的真相.因为确认序号是 54,因此报文段 14是报文段 12中确认的应答.

libnodelay 1.0.1发布 禁用Nagle算法的LD_PRELOAD库

libnodelay是一个禁用Nagle算法的LD_PRELOAD库.禁用Nagle算法可能导致对延迟敏感的应用程序使TCP性能得到改善.使用该库可能不能通过代码和混乱或含糊不清的配置选项. libnodelay 1.0.1该版本有一个严格的C编译器用户的安全被修复. 下载地址:http://bogomips.org/libnodelay.git/snapshot/libnodelay-1.0.1.tar.gz 安装说明: 将libnodelay.so安装在您的$HOME/lib中 $ make

【C/C++学院】0723-32位与64位/调戏窗口程序/数据分离算法/内存检索/二分查找法/myVC

[送给在路上的程序员] 对于一个开发者而言,能够胜任系统中任意一个模块的开发是其核心价值的体现. 对于一个架构师而言,掌握各种语言的优势并可以运用到系统中,由此简化系统的开发,是其架构生涯的第一步. 对于一个开发团队而言,能在短期内开发出用户满意的软件系统是起核心竞争力的体现. 每一个程序员都不能固步自封,要多接触新的行业,新的技术领域,突破自我. 32位与64位 地址与内存的关系 4G = 4*1024M = 4*1024*1024k = 4*1024*1024*1024 Byte字节 = 2

TCP协议疑难杂症全景分析

说明: 1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面 2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的 3).针对对象:对TCP已经有了全面了解的人.因为本文不会解析TCP头里面的每一个字段或者3次握手的细节,也不会解释慢启动和快速重传的定义 4).除了<TCP/IP详解>(卷一,卷二)以及<Unix网络编程>以及Linux源代码之外,学习网络更好的资源是RFC 5).本文给出一个提纲,如果想了解细节,请直接查阅RFC 6).翻

网络编程中Nagle算法和Delayed ACK的测试

Nagle算法的立意是良好的,避免网络中充塞小封包,提高网络的利用率.但是当Nagle算法遇到delayed ACK悲剧就发生了.Delayed ACK的本意也是为了提高TCP性能,跟应答数据捎带上ACK,同时避免糊涂窗口综合症,也可以一个ack确认多个段来节省开销.     悲剧发生在这种情况,假设一端发送数据并等待另一端应答,协议上分为头部和数据,发送的时候不幸地选择了write-write,然后再read,也就是先发送头部,再发送数据,最后等待应答.发送端的伪代码是这样 write(hea

【转载】网络编程中 Nagle 算法和 Delayed ACK 的测试

     Nagle 算法 的立意是良好的,是为了避免网络中充塞小封包,可以提高网络的利用率.但是当 Nagle 算法遇到 delayed ACK 悲剧就发生了.Delayed ACK 的本意也是为了提高 TCP 性能,在应答数据中捎带上 ACK,同时避免 糊涂窗口综合症 ,也可以一个 ACK 确认多个段来节省开销.     悲剧发生在这种情况,假设一端发送数据并等待另一端应答,协议上分为头部和数据,发送的时候不幸地选择了 write-write,然后再 read,也就是先发送头部,再发送数据,

TCP窗口知识汇总

最近两次面试都遇到的问题,有必要补缺. 可靠传输工作原理: 停止等待协议 超时重传 连续ARQ协议 使用滑动窗口,累积确认,回退N TCP可靠传输: 以字节为单位的滑动窗口 超时重传时间 选择确认sack TCP流量控制: 利用滑动窗口 发送零窗口报文后,非零窗口报文丢失.解决方法是持续计数器机制超时发送探测报文段. 糊涂窗口综合症 接收缓存慢,取数据很少,导致每次传输少.解决方法是让接收方等待一段时间或者等到接收缓存空闲一半. TCP拥塞控制: 方法分为开环控制和闭环控制.闭环控制基于反馈.