socket TCP_NODELAY选项

在元数据操作等小包传送时,发现性能不好,通过调试发现跟socket的TCP_NODELAY有很大关系。
TCP_NODELAY 和 TCP_CORK, 
这两个选项都对网络连接的行为具有重要的作用。许多UNIX系统都实现了TCP_NODELAY选项,但是,TCP_CORK则是Linux系统所独有的 而且相对较新;它首先在内核版本2.4上得以实现。此外,其他UNIX系统版本也有功能类似的选项,值得注意的是,在某种由BSD派生的系统上的 TCP_NOPUSH选项其实就是TCP_CORK的一部分具体实现。 
TCP_NODELAY和TCP_CORK基本上控制了包的“Nagle化”,Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。 John Nagle是Nagle算法的发明人,后者就是用他的名字来命名的,他在1984年首次用这种方法来尝试解决福特汽车公司的网络拥塞问题(欲了解详情请参 看IETF RFC 896)。他解决的问题就是所谓的silly window syndrome ,中文称“愚蠢窗口症候群”,具体含义是,因为普遍终端应用程序每产生一次击键操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据载荷以及40 个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞,。 Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为缺省配置了,但在我们看来,有些场合下把这一选项关掉也是合乎需要的。 
现在让我们假设某个应用程序发出了一个请求,希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。如果我们马上发 送数据,那么交互性的以及客户/服务器型的应用程序将极大地受益。例如,当我们正在发送一个较短的请求并且等候较大的响应时,相关过载与传输的数据总量相 比就会比较低,而且,如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的TCP_NODELAY选项来完成,这样就禁用了Nagle 算法。 
另外一种情况则需要我们等到数据量达到最大时才通过网络一次发送全部数据,这种数据传输方式有益于大量数据的通信性能,典型的应用就是文件服务器。应用 Nagle算法在这种情况下就会产生问题。但是,如果你正在发送大量数据,你可以设置TCP_CORK选项禁用Nagle化,其方式正好同 TCP_NODELAY相反(TCP_CORK 和 TCP_NODELAY 是互相排斥的)。下面就让我们仔细分析下其工作原理。 
假设应用程序使用sendfile()函数来转移大量数据。应用协议通常要求发送某些信息来预先解释数据,这些信息其实就是报头内容。典型情况下报头很 小,而且套接字上设置了TCP_NODELAY。有报头的包将被立即传输,在某些情况下(取决于内部的包计数器),因为这个包成功地被对方收到后需要请求 对方确认。这样,大量数据的传输就会被推迟而且产生了不必要的网络流量交换。 
但是,如果我们在套接字上设置了TCP_CORK(可以比喻为在管道上插入“塞子”)选项,具有报头的包就会填补大量的数据,所有的数据都根据大小自动地 通过包传输出去。当数据传输完成时,最好取消TCP_CORK 选项设置给连接“拔去塞子”以便任一部分的帧都能发送出去。这同“塞住”网络连接同等重要。 
总而言之,如果你肯定能一起发送多个数据集合(例如HTTP响应的头和正文),那么我们建议你设置TCP_CORK选项,这样在这些数据之间不存在延迟。能极大地有益于WWW、FTP以及文件服务器的性能,同时也简化了你的工作。示例代码如下: 

intfd, on = 1; 
… 
/* 此处是创建套接字等操作,出于篇幅的考虑省略*/ 
… 
setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* cork */ 
write (fd, …); 
fprintf (fd, …); 
sendfile (fd, …); 
write (fd, …); 
sendfile (fd, …); 
… 
on = 0; 
setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* 拔去塞子 */ 
或者
setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char*)&yes,sizeof(int));
### TCP_NODELAY 选项的作用 TCP_NODELAY 选项的主要作用是禁用 Nagle 算法。Nagle 算法是一种用于减少小数据包数量的机制,它通过将多个小数据包合并成一个较大的数据包来发送,从而减少网络拥塞。然而,这种合并操作会引入延迟,因为数据需要等待一段时间以合并更多的数据[^1]。 当启用 TCP_NODELAY 选项时,Nagle 算法被禁用,允许小数据包立即发送,从而减少延迟。这对于需要低延迟的应用程序(如实时通信、在线游戏、HTTP2 等)非常重要[^2]。 ### TCP_NODELAY 选项的使用方法 在 Linux 系统中,TCP_NODELAY 选项可以通过 `setsockopt()` 函数在套接字层面进行配置。以下是一个简单的 C 语言示例,展示如何启用 TCP_NODELAY 选项: ```c #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> int enable_nodelay(int sockfd) { int optval = 1; socklen_t optlen = sizeof(optval); if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, optlen) < 0) { // Handle error return -1; } return 0; } ``` 在这个示例中,`TCP_NODELAY` 是选项名称,`optval` 被设置为 1 以启用该选项,`optlen` 是选项值的长度。 ### 检查 TCP_NODELAY 选项是否生效 要检查 TCP_NODELAY 选项是否已正确启用,可以使用 `ss -ti` 命令。该命令将显示 TCP 连接的信息,包括 `nodelay` 标志的状态。例如: ```bash ss -ti ``` 输出中的 `nodelay` 标志表示该连接是否启用了 TCP_NODELAY 选项[^1]。 ### 系统级低延迟支持 如果需要在整个系统范围内实现低延迟,可以考虑调整 `net.ipv4.tcp_low_latency` 内核参数。这个参数控制 TCP 协议栈的行为,使其更倾向于低延迟而不是高吞吐量。可以通过以下命令临时修改该参数: ```bash sysctl -w net.ipv4.tcp_low_latency=1 ``` 要使更改永久生效,可以将其添加到 `/etc/sysctl.conf` 文件中: ```bash echo "net.ipv4.tcp_low_latency=1" >> /etc/sysctl.conf sysctl -p ``` 通过这种方式,可以在系统级别上优化网络性能以实现更低的延迟[^1]。 ### MSS 和 MTU 的关系 在讨论 TCP_NODELAY 时,了解 MSS(Maximum Segment Size)和 MTU(Maximum Transmission Unit)的关系也很重要。MTU 是一个网络包的最大长度,通常在以太网中为 1500 字节。MSS 是除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度,通常最大为 1460 字节[^3]。 HTTP2 协议默认启用了 TCP_NODELAY 选项,因为其设计特点(在一个 TCP 连接上进行所有 HTTP 请求,并且请求头部是压缩的)增加了小数据包的可能性。多个小数据包的大小总和小于 MSS 会导致延迟现象,因此启用 TCP_NODELAY 是必要的。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值