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 左右(2RTT+40ms=42ms)。flower 服务器之所以有 40ms 延时发送 ack,这是因为受到了延时的 ack 算法影响。该知识点在介绍 tcp 的时候已经详细的讲解过了。

在这种情况下,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
0 0