TCP_NODELAY和Nagle算法

原创 2016年06月01日 21:08:46

一、概述

在网络拥塞控制领域,有一个非常有名的算法叫做Nagle算法(Nagle algorithm),这是使用它的发明人John Nagle的名字来命名的,John Nagle在1984年首次用这个算法来尝试解决福特汽车公司的网络拥塞问题(RFC 896)。

该问题的具体描述是:如果我们的应用程序一次产生1个字节的数据,而这个1个字节数据又以网络数据包的形式发送到远端服务器,那么就很容易导致网络由于太多的数据包而过载。比如,当用户使用Telnet连接到远程服务器时,每一次击键操作就会产生1个字节数据,进而发送出去一个数据包,所以,在典型情况下,传送一个只拥有1个字节有效数据的数据包,却要发费40个字节长包头(即ip头20字节+tcp头20字节)的额外开销,这种有效载荷(payload)利用率极其低下的情况被统称之为愚蠢窗口症候群(Silly Window Syndrome)。可以看到,这种情况对于轻负载的网络来说,可能还可以接受,但是对于重负载的网络而言,就极有可能承载不了而轻易的发生拥塞瘫痪。

针对上面提到的这个状况,Nagle算法的改进在于:如果发送端欲多次发送包含少量字符的数据包(一般情况下,后面统一称长度小于MSS的数据包为小包,与此相对,称长度等于MSS的数据包为大包,为了某些对比说明,还有中包,即长度比小包长,但又不足一个MSS的包),则发送端会先将第一个小包发送出去,而将后面到达的少量字符数据都缓存起来而不立即发送,直到收到接收端对前一个数据包报文段的ACK确认、或当前字符属于紧急数据,或者积攒到了一定数量的数据(比如缓存的字符数据已经达到数据包报文段的最大长度)等多种情况才将其组成一个较大的数据包发送出去。


二、Nagle算法

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

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

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



这里两个问题:

1.(这个上面已经解释过了)为什么B块要在A块的ACK到达之后才发送?

Nagle算法。

2.就是A块数据的ACK为什么40ms之后才收到?

因为TCP/IP中不仅仅有Nagle算法(Nagle‘s Algorithm),还有一个ACK延迟机制(TCP Delayed Ack) 。当Server端收到数据之后,它并不会马上向client端发送ACK,而是会将ACK的发送延迟一段时间(假设为t),它希望在t时间内server端会向client端发送应答数据,这样ACK就能够和应答数据一起发送,就像是应答数据捎带着ACK过去。


也就是如果一个 TCP 连接的一端启用了Nagle算法,而另一端启用了ACK延时机制,而发送的数据包又比较小,则可能会出现这样的情况:发送端在等待接收端对上一个packet的Ack才发送当前的packet,而接收端则正好延迟了此Ack的发送,那么这个正要被发送的packet就会同样被延迟。当然Delayed Ack是有个超时机制的,而默认的超时正好就是40ms。




现代的 TCP/IP 协议栈实现,默认几乎都启用了这两个功能,那岂不每次都会触发这个延迟问题?事实不是那样的。仅当协议的交互是发送端连续发送两个packet,然后立刻read的时候才会出现问题。



三、解决方案


1.优化协议
连续 write 小数据包,然后 read 其实是一个不好的网络编程模式,这样的连续 write 其实应该在应用层合并成一次 write。

2.开启TCP_NODELAY
简单地说,这个选项的作用就是禁用Nagle算法,禁止后当然就不会有它引起的一系列问题了。使用setsockopt可以做到:

static void _set_tcp_nodelay(int fd) {
int enable = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&enable, sizeof(enable));
}






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

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

在linux编程中,以下哪个TCP的套接字选项与nagle算法的开启和关闭有关?----腾讯2016研发工程师在线模拟笔试题

在linux编程中,以下哪个TCP的套接字选项与nagle算法的开启和关闭有关? 正确答案: B   TCP_MAXSEG TCP_NODELAY TCP_...

TCP Nagle算法详解

转: http://bbs.chinaunix.net/thread-3767363-1-1.html 在网络拥塞控制领域,我们知道有一个非常有名的算法叫做Nagle算法(Nagle algori...

Nagle算法

说明:本文是最近项目上使用tcp时遇到的问题找到的原因,参考了网络上的几篇文章整理出来,如有版权问题,请留言。    Nagle算法用于对缓冲区内的一定数量的消息进行自动连接。该处理过程(称为Nag...

TCP-IP详解:Nagle算法

Small Packet Problem 在使用一些协议通讯的时候,比如Telnet,会有一个字节字节的发送的情景,每次发送一个字节的有用数据,就会产生41个字节长的分组,20个字节的IP Hea...

Nagle 算法

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

TCP/IP详解--TCP/UDP优化设置总结& MTU的相关介绍

首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层。    其中以太网(Ethernet)的数据帧在链路层    IP包在网络层    TCP或UDP包在传输层    TCP或UDP...

网络编程nagle算法和TCP_NODELAY

之前写过一篇blog ,描述了用mina的时候写socket发现的一个诡异现象,当时将多个小数据写操作合并成一个写操作,问题就没了。Chenshuo同学还建议我设置TCP_NODELAY,只是后来因为...

网络编程之nagle算法和TCP_NODELAY

之前写过一篇blog ,描述了用mina的时候写socket发现的一个诡异现象,当时将多个小数据写操作合并成一个写操作,问题就没了。Chenshuo同学还建议我设置TCP_NODELAY,只是后来因...

网络编程之nagle算法和TCP_NODELAY

现在大概明白,是由于nagle算法在捣乱。TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:TCP_NODELAY和Nagle算法
举报原因:
原因补充:

(最多只允许输入30个字)