注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

Nagle算法的应用---网络通信中的粘包原因  

2014-05-06 21:39:36|  分类: 网络服务编程技术 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Nagle算法的应用

在网络编程中,大家经常遇到这样一些情况,发送的数据包如果特别小,只有一两个字节,那么加上各层通信协议上的头和校验位,会发现,真正的传输的数据反而非常少。那么数据传输的效率会低到无法忍受的地步。从键盘输入的一个字符,占用一个字节,可能在传输上造成41字节的包,其中包括1字节的有用信息和40字节的标题数据。

这时候,有人就出手解决了这个问题,首先是在福特公司使用的。具体看:

http://lbc2100.blog.163.com/blog/static/1505536020126192843493/

http://blog.163.com/li_xiang1102/blog/static/607140762011111103213616/

当然有的时候儿,可能你会需要一个个的发,那么就得通过下面的函数来禁止这个算法:

SetSockOpt(s,IPPROTO_TCP,TCP_NODELAY,(const char*)&bNodelayt,sizeof(BOOL));

TCP_NODELAY就是禁止Nagle算法,立刻发送数据。

 TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

    Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段。 所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。

    Nagle算法的规则(可参考tcp_output.c文件里tcp_nagle_check函数注释):

    1)如果包长度达到MSS(最大发送单元,一般来说可以认为MTU),则允许发送;

    2)如果该包含有FIN(网络关闭),则允许发送;

    3)设置了TCP_NODELAY选项,则允许发送;

    4)未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;

    5上述条件都未满足,但发生了超时(一般为200ms),则立即发送。Nagle算法的应用

上面的函数SetSockOpt还有一个选项设置: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算法的话,则可能做不到这一点。

通过上面的说明了一些什么呢?那就是网络传输中的粘包,这就是造成粘包的主要原因。分包的原因就更简单了,看一下TCP传送的机制就知道了,MTU就是制约的一个主要因素,其它也有好几个,包括拥塞等。

有兴趣可以看一下内核相关方面的代码。

  评论这张
 
阅读(456)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017