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

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

Nagle算法的规则(:

(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的数据包,然后再发送尾部的小数据包,其间不再延时等待。(假设网络不阻塞且接收窗口足够大)。

举个例子,一开始client端调用socket的write操作将一个int型数据(称为A块)写入到网络中,由于此时连接是空闲的(也就是说还没有未被确认的小段),因此这个int型数据会被马上发送到server端,接着,client端又调用write操作写入‘\r\n’(简称B块),这个时候,A块的ACK没有返回,所以可以认为已经存在了一个未被确认的小段,所以B块没有立即被发送,一直等待A块的ACK收到(大概40ms之后),B块才被发送。整个过程如图所示:

这里还隐藏了一个问题,就是A块数据的ACK为什么40ms之后才收到?这是因为TCP/IP中不仅仅有nagle算法,还有一个TCP确认延迟机制 。当Server端收到数据之后,它并不会马上向client端发送ACK,而是会将ACK的发送延迟一段时间(假设为t),它希望在t时间内server端会向client端发送应答数据,这样ACK就能够和应答数据一起发送,就像是应答数据捎带着ACK过去。在我之前的时间中,t大概就是40ms。这就解释了为什么'\r\n'(B块)总是在A块之后40ms才发出。

当然,TCP确认延迟40ms并不是一直不变的,TCP连接的延迟确认时间一般初始化为最小值40ms,随后根据连接的重传超时时间(RTO)、上次收到数据包与本次接收数据包的时间间隔等参数进行不断调整。另外可以通过设置TCP_QUICKACK选项来取消确认延迟。

关于TCP确认延迟的详细介绍可参考:http://blog.csdn.net/turkeyzhou/article/details/6764389

2. TCP_NODELAY 选项

默认情况下,发送数据采用Negale 算法。这样虽然提高了网络吞吐量,但是实时性却降低了,在一些交互性很强的应用程序来说是不允许的,使用TCP_NODELAY选项可以禁止Negale 算法。

此时,应用程序向内核递交的每个数据包都会立即发送出去。需要注意的是,虽然禁止了Negale 算法,但网络的传输仍然受到TCP确认延迟机制的影响。

3. TCP_CORK 选项

所谓的CORK就是塞子的意思,形象地理解就是用CORK将连接塞住,使得数据先不发出去,等到拔去塞子后再发出去。设置该选项后,内核会尽力把小数据包拼接成一个大的数据包(一个MTU)再发送出去,当然若一定时间后(一般为200ms,该值尚待确认),内核仍然没有组合成一个MTU时也必须发送现有的数据(不可能让数据一直等待吧)。

然而,TCP_CORK的实现可能并不像你想象的那么完美,CORK并不会将连接完全塞住。内核其实并不知道应用层到底什么时候会发送第二批数据用于和第一批数据拼接以达到MTU的大小,因此内核会给出一个时间限制,在该时间内没有拼接成一个大包(努力接近MTU)的话,内核就会无条件发送。也就是说若应用层程序发送小包数据的间隔不够短时,TCP_CORK就没有一点作用,反而失去了数据的实时性(每个小包数据都会延时一定时间再发送)。

4. Nagle算法与CORK算法区别

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

实际上Nagle算法并不是很复杂,他的主要职责是数据的累积,实际上有两个门槛:一个就是缓 冲区中的字节数达到了一定量,另一个就是等待了一定的时间(一般的Nagle算法都是等待200ms);这两个门槛的任何一个达到都必须发送数据了。一般 情况下,如果数据流量很大,第二个条件是永远不会起作用的,但当发送小的数据包时,第二个门槛就发挥作用了,防止数据被无限的缓存在缓冲区不是好事情哦。 了解了TCP的Nagle算法的原理之后我们可以自己动手来实现一个类似的算法了,在动手之前我们还要记住一个重要的事情,也是我们动手实现Nagle算 法的主要动机就是我想要紧急发送数据的时候就要发送了,所以对于上面的两个门槛之外还的增加一个门槛就是紧急数据发送。

对于我现在每秒钟10次数据发送,每次数据发送量固定在85~100字节的应用而言,如果采用默认的开启Nagle算法,我在发送端,固定每帧数据85个,间隔100ms发送一次,我在接受端(阻塞方式使用)接受的数据是43 138交替出现,可能就是这个算法的时间阈值问题,如果关闭Nagle算法,在接收端就可以保证数据每次接收到的都是85帧。

Nagle算法适用于小包、高延迟的场合,而对于要求交互速度的b/s或c/s就不合适了。socket在创建的时候,默认都是使用Nagle算法的,这会导致交互速度严重下降,所以需要setsockopt函数来设置TCP_NODELAY为1.不过取消了Nagle算法,就会导致TCP碎片增多,效率可能会降低。

关闭nagle算法,以免影响性能,因为控制时控制端要发送很多数据量很小的数据包,需要马上发送。

const char chOpt = 1;

int nErr = setsockopt(pContext->m_Socket, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char));

if (nErr == -1)

{

TRACE(_T("setsockopt() error\n"),WSAGetLastError());

return;

}

socket中的nagle算法相关推荐

  1. 在c语言中如何屏蔽一段程序,如何在用C语言关闭TCP程序中的Nagle算法

    TCP为了防止在网络中过多的小分组会导致阻塞,因此提供了Nagle算法:要求一个TCP连接上最多只能有一个未被确认的未完成的小分组,在该分组的确认到达之前不能发送其他的小分组.相反,TCP收集这些少量 ...

  2. 【TCP/IP】Nagle算法

    Nagle算法 1.为什么要引入Nagle算法 Nagle算法主要是为了防止网络连接中充斥着<MSS的分组.小的分组一方面会造成网络拥塞,另外一方面由于网络传输过程中,用户程序需要传递的内容需要 ...

  3. TCP-IP详解:Nagle算法

    参考书籍:TCP/IP详解,卷1:协议 Small Packet Problem 在使用一些协议通讯的时候,比如Telnet,会有一个字节字节的发送的情景,每次发送一个字节的有用数据,就会产生41个字 ...

  4. 【Java 网络编程】客户端 Socket 配置 ( 超时时间 | 端口复用 | Nagle 算法 | 心跳包机制 | 连接关闭机制 | 缓冲区大小 | 性能权重设置 | 紧急数据设置 )

    文章目录 I 设置读取超时时间 II Socket 复用绑定端口设置 III 开启 Nagle 算法 ( 沾包 ) IV 心跳包机制 V 连接关闭处理 VI Socket 紧急数据内敛设置 VII S ...

  5. socket属性心跳、Nagle 算法

    Nagle 算法 为防止因数据包过多而发生网络过载, Nagle算法在1984年诞生了.它应用于TCP层,非常简单.其使用与否会导致如图所示差异 Nagle算法:"只有收到前一数据的ACK消 ...

  6. 网络协议:TCP保活机制和Nagle算法

    一 Nagle算法背景 有时候,我们可能会遇到一些很小的分组,比如,20字节的IP首部,20字节的TCP首部和1字节的数据,如果很多这样的小分组数据,在局域网一般不会出现拥塞,但是在广域网就可有可能. ...

  7. 再次谈谈TCP的Nagle算法与TCP_CORK选项

    事件回放 使用OpenVPN传输虚拟桌面流量,终端上有明显逐帧刷屏现象,网络环境为百兆局域网. 分析 1.首先将OpenVPN改为TCP模式,因为局域网环境下TCP和UDP差别不大,不会引起重传叠加问 ...

  8. Nagle算法和延迟确认

    TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认.为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据.(一个连接会设置MS ...

  9. TCP-Nagle:代码版本重新解释Nagle算法

    开年来的第一份工作,就是在最新的内核上打补丁. 可没想到Nagle算法也被我冲进了去年的垃圾桶里. 在网上找了一些资料,理论很快被消化,但看了看内核的实现,久久没能动弹.坐了一天,才摸索出来点什么,觉 ...

最新文章

  1. 阿里发布2019十大科技趋势,5G仍是主要生产力
  2. c语言全局变量符号,C语言中的 @ 符号是什么意思?
  3. Echarts与Highcharts的比较
  4. 移动Sql Server数据库的脚本
  5. HBase shell执行批量脚本
  6. Eclipse中SVN过滤指定文件夹或文件下内容
  7. C++第9周(春)项目5 - 一元一次方程类
  8. 我的电脑能装苹果吗?
  9. 【第126期】游戏策划:给@毛毛团的简历分析
  10. graythresh函数(OTSU算法)
  11. /etc/login.defs配置文件详解
  12. linux安装程序企鹅,在linux下安装fcitx(小企鹅)中文输入法
  13. 流体连续性方程【The Equation of Continuity】
  14. flutter 初视回味
  15. UART BootROM
  16. Java 多态的薪酬计算的练习
  17. libreCAD使用
  18. python写情书_Python程序员用文字加密的方式,给女程序员写情书,一周后牵手回家_TONOW...
  19. 计算机网络安全论文选题提纲,计算机网络安全毕业论文提纲
  20. java:JDBC连接数据库实现用户管理系统

热门文章

  1. MapReduce-流量统计求和-步骤分析
  2. 缺省参数-回顾列表的排序方法明确缺省参数的概念及作用
  3. python请输入_不断提示用户输入Python
  4. php 微信机器人_微信小程序机器人自动客服功能
  5. java 车站分级问题_【NOIP2013 普及组】车站分级
  6. ubuntu tail、history|grep 、alias命令
  7. modbus poll\slave
  8. HMAC-SHA1加密
  9. 远程管理,无需在机房来回穿梭
  10. Jmeter(7)调试工具---HTTP Mirror Server