详解Socket编程---TCP_NODELAY选项

Nagle算法描述

Socket编程中,TCP_NODELAY选项是用来控制是否开启Nagle算法,该算法是为了提高较慢的广域网传输效率,减小小分组的报文个数,完整描述:

该算法要求一个TCP连接上最多只能有一个未被确认的小分组,在该小分组的确认到来之前,不能发送其他小分组。

这里的小分组指的是报文长度小于MSS(Max Segment Size)长度的分组(MSS是在TCP握手的时候在报文选项里面进行通告的大小,主要是用来限制另一端发送数据的长度,防止IP数据包被分段,提高效率,一般是链路层的传输最大传输单元大小减去IP首部与TCP首部大小)。

如果小分组的确认ACK一直没有回来,那么就可能会触发TCP超时重传的定时器。

下面是一个简单的示意图,开启了Nagle算法与没有开启:

nagle

抓包分析

默认开启Nagle算法

由于局域网内延迟低,不容易看到开启Nagle算法的效果,所以专门整个腾讯云的服务器测试,延迟在40毫秒左右。

ping

Java代码与Unix C的Socket接口类似,这里使用Java代码作为示例简单一点。默认情况下Nagle算法是开启的,即socket.getTcpNoDelay()返回的数值为false,我们先分析这种场景。

Receiver的代码:

try (ServerSocket serverSocket = new ServerSocket()) {
    serverSocket.bind(new InetSocketAddress(10086));//wildcard ip
    Socket socket = serverSocket.accept();
    System.out.println("Accept New Socket");
    System.out.println("Tcp No Delay : " + socket.getTcpNoDelay());
    InputStream is = socket.getInputStream();
    OutputStream os = socket.getOutputStream();
    int result;
    while((result = is.read()) != -1) {
        System.out.println((char)result);
    }
    TimeUnit.MINUTES.sleep(1);
}

Sender的代码:

try(Socket socket = new Socket()) {
    socket.connect(new InetSocketAddress("212.64.20.XX", 10086));
    System.out.println("Tcp No Delay : " + socket.getTcpNoDelay());
    InputStream is = socket.getInputStream();
    OutputStream os = socket.getOutputStream();
    for (byte c : "TCP_NO_DELAY".getBytes()) {
        TimeUnit.MILLISECONDS.sleep(10);
        os.write(c);
        os.flush();
    }
    TimeUnit.MINUTES.sleep(1);
} catch (IOException e) {
    e.printStackTrace();
}

与服务器的延时在40毫秒左右,所以Sender这里每隔10毫秒就发送一次就可以演示出累计的小分组在收到ACK后才发送。注意如果是TCP发送的数据延迟还包含链路来回的延迟与Receiver捎带确认的延迟。

这里抓包工具使用的是tcpdump,导出pcap文件后再使用wireshark观察发送与接收数据的过程。

$ sudo tcpdump -v port 10086 -w TCP_DELAY.pcap

cap
  • 首先第一行到第三行是TCP三次握手的报文,可以看到双方都各自通告的MSS大小,发送端的报文小于这个大小就可以理解为小分组

  • 第四行是Sender向Receiver发送的第一个字符'T',对应的Len=1

  • 第五行是Receiver回来对第四行发送消息的确认ACK

  • 第六行,前面使用ping测试的延迟在40毫秒左右,而我们每10毫秒就会一个字符写到OS维护的发送缓冲区,所以确认ACK回来后,就已经累计了4个字符"CP_N",发送的数据就是这4个字符

  • 之后的流程和上面的类似,可能会出现发送不是4个字符的情况,出现的原因就是延迟可能小于或者大于40毫秒

下面是使用wireshark导出的时序图帮助进一步帮助理解这个流程。

flow
关闭Nagle算法

只需要在发送数据之前对Socket调用一个简单的方法就可以关闭Nagle算法:

socket.setTcpNoDelay(true);

直接抓包,看下报文:

cap

可以看到,在Sender每10毫秒发送一个字符,不需要等到Receiver发送确认ACK,就继续发送,没有将数据放到OS维护的缓冲区。

下面是使用wireshark导出的时序图:

flow

总结

这个选项应该根据适合的场景进行判断关闭与否,例如实时性要求比较高的场景,类似用户鼠标操作,键盘输入,触摸屏事件输入,状态更新等这种连续的小分组数据,需要在对端立刻呈现,让用户尽可能感受不到延迟。但是如果网络延迟比较高,采用这种方式,那么会导致网路利用率下降。

一般类似HTTP协议请求响应的模型的场景不太需要考虑禁用这个算法,因为在一条TCP连接上发送小报文,不管多小都代表了服务端任务执行的指示,完成了这个请求之后才能继续执行下一个请求,即使Sender端提前发送过去也没有作用,所以开启Nagle算法是能够优化网络传输的,并且在Receiver端有捎带延迟确认,省掉单独的ACK确认进一步优化小分组传输。

另外HTTP2与HTTP协议不同,HTTP2是在一条TCP连接上进行所有HTTP请求,并且请求头部是压缩的就进一步加大了请求小分组的可能性,多个小分组HTTP请求并且分组大小的和小于MSS就会导致有延迟的现象,所以HTTP2的实现TCP_NODELAY选项是默认开启的。关于这点可以参考HTTP2对TCP_NODELAY的描述

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 1.这篇文章不是本人原创的,只是个人为了对这部分知识做一个整理和系统的输出而编辑成的,在此郑重地向本文所引用文章的...
    SOMCENT阅读 13,051评论 6 174
  • 套接字选项SO_RESUEADDR 即使端口处于2MSL状态,使用该选项,仍然能够在该端口建立连接。服务器常会设置...
    Myth52125阅读 1,403评论 0 0
  • 21.1 引言 TCP提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确认都有可能会丢失。T...
    张芳涛阅读 2,995评论 0 8
  • 个人认为,Goodboy1881先生的TCP /IP 协议详解学习博客系列博客是一部非常精彩的学习笔记,这虽然只是...
    贰零壹柒_fc10阅读 5,051评论 0 8
  • 人需要突破自己的舒适区,进入到更大的世界中,而舒适区的边界,总是由恐惧所形成。恐惧,常常是在揭示着生命的真谛,越是...
    Bang_成长之路阅读 144评论 0 0