55-套接字选项(TCP_NODELAY)
来源:互联网 发布:作为科学家的子女知乎 编辑:程序博客网 时间:2024/05/21 14:42
开启本选项,将禁止 Nagle 算法。有关 Nagle 算法的细节,请参考《TCP 协议(Nagle) 》。
1. 程序路径
代码托管在 gitos 上,请使用下面的命令获取:
git clone https://git.oschina.net/ivan_allen/unp.git
如果你已经 clone 过这个代码了,请使用 git pull
更新一下。本节程序所使用的程序路径是 unp/program/options/opt
。
2. 回忆 Nagle
Nagle 算法的目的是为了减少网络中小分组的数目。“小”分组(tiny gram) 指是是小于 MSS 的分组。它利用收到 ack 前这一小段时间“攒”数据,收到 ack 后,再将“攒”起来的小分组合并成一个大分组一次性发出去。
在局域网上,通常我们察觉不到 Nagle 算法对客户进程的影响。但是在广域网上,小分组所需要的确认时间可能长达 1 秒,这样客户端就会有非常明显的延时。如果受延时的 ack 影响,这种延时会更加明显(参考 TCP 协议(迟到的 ACK —— Windows ) 和 TCP 协议(迟到的 ACK—— Linux) )。
3. 如何关闭 Nagle 算法
TCP_NODELAY 选项可以用来关闭 Nagle 算法,具体代码如下:
int onoff = 1;ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &onoff, sizeof(onoff));if (ret < 0) perror("setsockopt");
4. Nagle 算法与 write-write-read
看下面一小段客户端的程序:
// clientwhile(1) { write(sockfd, buf, 4); write(sockfd, buf, 396); read(sockfd, buf, 1024);}
第 2 次 write 的数据会一直驻留在发送缓冲区中,直到第一个 4 字节的小分组被确认。而服务器并没有数据要发送给客户端,因此会发送延时的 ack,比如已经过了 40ms,客户端才会收到这 4 字节的小分组的确认。接下来 TCP 发送 396 字节大小的分组,等待服务器处理完后发送数据给客户端,客户端从 read 返回。
图1 write-write-read
如果 RTT 非常小,比如只有 1 ms,那么上面的调用过程,将会在 read 上阻塞约 42 ms 左右(
在这种情况下,Nagle 算法并没有什么好处,反而会降低数据传输效率。有三种方法可以修正这种问题:
- 使用 writev 函数,聚集写。
- 在应用层将前 4 个字节和后 396 字节复制到单个缓冲区,然后调用一次 write.
- 使用 TCP_NODELAY 关闭 Nagle 算法。unp 中提到说这是最不可取的方法,而且有损于网络,通常不应该考虑。(很多博客和文章都推荐关闭 Nagle?Nginx 默认也是关闭了 Nagle 算法的。陈硕老师也推荐关闭 Nagle 算法……所以,大家以后该怎么做?)
5. 实验
5.1 关闭 Nagle 算法
- flower 上启动服务器
$ ./opt -s -h flower --slowread 4096
- sun 上启动客户端,注意参数
// 选项 --writesize 1,表示客户端每次只 write 一个字节// --nodelay 表示关闭 Nagle 算法$ ./opt -h flower --nodelay --writesize 1
- 在客户端输入
'helloworld'
,然后回车。一共 11 个字符包含了字符'\n'
。
图1 关闭 Nagle 算法的情况
可以看到,关闭 Nagle 时,只要有小分组就立即发送出去。
5.2 打开 Nagle 算法
- flower 上启动服务器
$ ./opt -s -h flower --slowread 4096
- sun 上启动客户端,注意参数
// 选项 --writesize 1,表示客户端每次只 write 一个字节// 默认情况下 Nagle 算法是开启的$ ./opt -h flower --writesize 1
- 在客户端输入
'helloworld'
,然后回车。一共 11 个字符包含了字符'\n'
。
图2 开启 Nagle 算法的情况
可以看到,客户端会将小分组收集起来,合并成一个大分组一次发送出去。
6. 总结
- 知道 Nagle 算法干了什么事
- 知道如何关闭 Nagle
- 55-套接字选项(TCP_NODELAY)
- socket TCP_NODELAY选项
- 套接字选项(getsockopt()与setsockopt())
- 套接字选项(SO_RCVBUF和SO_SNDBUF)
- 51-套接字选项(概述)
- 53-套接字选项(SO_REUSEADDR)
- 54-套接字选项(SO_LINGER)
- 56-套接字选项(TCP_CORK)
- 常用套接字选项(SOL_SOCKET级别)
- 常用套接字选项(SOL_SOCKET级别)
- 套接字选项
- 套接字选项
- 套接字选项setsockopt()
- 通用套接字选项
- 7 套接字选项
- 套接字选项介绍
- 套接字选项
- 套接字选项
- 词向量之word2vec(2)
- [VR][Daydream]Ch 1 : Development Environment
- ActiveRecord::Fixture::FixtureError: table "users" has no column named "activated_at".
- MyBatis crud操作
- 二叉查找树--查找、删除、插入(Java实现)
- 55-套接字选项(TCP_NODELAY)
- 属性动画:基本使用和组合动画
- 如何调试其他项目的压缩JS文件
- jquery事件机制扩展插件 jquery鼠标右键事件
- Android studio中生成引用.aar和.jar的方法详解
- centos7 minial 环境下安装pptpd
- flash代替epcs
- Linux学习篇第二章~unit5
- javaSE_8系列博客——Java语言的特性(二)--高级语言的基础知识(3)-- 基本数据类型的默认值