TCP-Nagle:代码版本重新解释Nagle算法

article/2025/7/23 9:36:44

开年来的第一份工作,就是在最新的内核上打补丁。

可没想到Nagle算法也被我冲进了去年的垃圾桶里。

在网上找了一些资料,理论很快被消化,但看了看内核的实现,久久没能动弹。坐了一天,才摸索出来点什么,觉得需要一份代码解释TCP-Nagle的版本说明,这样和Nagle算法的黑盒解释,才能对TCP-Nagle有全面的理解。

于是,有了本文。

Nagle算法

RFC对Nagle算法解释

Nagle’s algorithm, named after John Nagle, is a means of improving the efficiency of TCP/IP networks
by reducing the number of packets that need to be sent over the network.
Nagle’s algorithm works by combining a number of small outgoing messages, and sending them
all at once. Specifically, as long as there is a sent packet for which the sender has received no
acknowledgment, the sender should keep buffering its output until it has a full packet’s worth of output,
so that output can be sent all at once.
Nagle’s algorithm purposefully delays transmission, increasing bandwidth efficiency at the expense of latency.

中文意思是:TCP-Nagle避免发送大量的小包(阻塞小包,粘合成大包),减少传输次数,但会有延迟的牺牲。

至于为什么会这样,大佬的文章已经有详细的展开,最后会贴上链接,欢迎去阅读。

TCP-Nagle的逻辑

if there is new data to sendif the window size >= MSS and available data is >= MSSsend complete MSS segment nowelseif there is unconfirmed data still in the pipeenqueue data in the buffer until an acknowledge is receivedelsesend data immediatelyend ifend if
end if 

TCP-Nagle 图解

在这里插入图片描述

Nagle图解完全依赖最新的内核实现。

可以看出,代码的实现短小精悍。那么来,详细解释下。

TCP-Nagle代码版本

TCP-Nagle显式标识事件

/* Flags in tp->nonagle */
#define TCP_NAGLE_OFF		1	/* Nagle's algo is disabled */
#define TCP_NAGLE_CORK		2	/* Socket is corked	    */
#define TCP_NAGLE_PUSH		4	/* Cork is overridden for already queued data */

除了这三个事件外,nonagle = 0 。

代码解释TCP-Nagle

TCP-Nagle仅仅对新报文有用,这使得它的实现只在tcp_write_xmit里。
tcp_transmit_skb前,TCP会优先判断报文发送的时机——可靠性检查,TCP-Nagle是一种影响发送的因素,目的是为了减少小包的发送。

if (tso_segs == 1) {if (unlikely(!tcp_nagle_test(tp, skb, mss_now,(tcp_skb_is_last(sk, skb) ?nonagle : TCP_NAGLE_PUSH))))break;} else {if (!push_one &&tcp_tso_should_defer(sk, skb, &is_cwnd_limited,&is_rwnd_limited, max_segs))break;}

实际上,tcp_nagle_testtcp_tso_should_defer都是TCP-Nagle,其中tcp_tso_should_defer讨论的是有GSO/TSO机制的介入,除了处理细节更复杂些,其他的道理和tcp_nagle_test相通,所以这里仅介绍tcp_nagle_test

这里有个细节,tcp_skb_is_last(sk, skb) ? nonagle : TCP_NAGLE_PUSH保证了Nagle仅对发送队列sk->sk_write_queue最后一个skb有作用,原因是粘包只能发生在最后一个skb上。这也在tcp_nagle_test的具体实现中有提及。

接下来,看下TCP-Nagle的主战场tcp_nagle_test的实现。

/* Return true if the Nagle test allows this packet to be* sent now.*///表明tcp_nagle_test返回true意味TCP-Nagle不生效,false才会启用Nagle粘包。
static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, unsigned int cur_mss, int nonagle)
{/* Nagle rule does not apply to frames, which sit in the middle of the* write_queue (they have no chances to get new data).** This is implemented in the callers, where they modify the 'nonagle'* argument based upon the location of SKB in the send queue.*/if (nonagle & TCP_NAGLE_PUSH)return true;/* Don't use the nagle rule for urgent data (or for the final FIN). */if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN))return true;if (!tcp_nagle_check(skb->len < cur_mss, tp, nonagle))return true;return false;
}

tcp_nagle_test的实现表明TCP-Nagle会受到很多条件限制。

前面的条件很直白,TCP_NAGLE_PUSH、 tcp_urg_mode(tp)、 (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)都表示数据包必须立即发送。

读TCP-Nagle时,有些误区是在tcp_nagle_check(skb->len < cur_mss, tp, nonagle)中出现的。

所以,tcp_nagle_check值得看看。

/* Return false, if packet can be sent now without violation Nagle's rules:* 1. It is full sized. (provided by caller in %partial bool)* 2. Or it contains FIN. (already checked by caller)* 3. Or TCP_CORK is not set, and TCP_NODELAY is set.* 4. Or TCP_CORK is not set, and all sent packets are ACKed.*    With Minshall's modification: all sent small packets are ACKed.*/
static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp,int nonagle)
{return partial &&((nonagle & TCP_NAGLE_CORK) ||(!nonagle && tp->packets_out && tcp_minshall_check(tp)));
}

又是一堆条件。可是,在这里需要小心,所以我们仔细看看。

tcp_nagle_check的第一个行参是bool partial,上面传递的参数是skb->len < cur_mss,表明TCP-Nagle要生效的第一个条件是skb所有的数据存储长度在小于MSS值,这意味着一旦skb包的所有数据大小大于等于MSS时,立刻发出数据包。

这里严格的来说,TCP-Nagle并不是一个完全的包停-等协议。

再看看小于MSS时,后面使能TCP-Nagle的条件,即skb所有数据长度小于MSS值的后续条件。

((nonagle & TCP_NAGLE_CORK) ||(!nonagle && tp->packets_out && tcp_minshall_check(tp)))

第一个条件,(nonagle & TCP_NAGLE_CORK),TCP_NAGLE_CORK标识显式注定了TCP-Nagle使能。

若没有TCP_NAGLE_CORK,第二个条件也可以使能TCP-Nagle。(!nonagle && tp->packets_out && tcp_minshall_check(tp))表明:

  1. nonagle没有被标记TCP_NAGLE_OFF,原因是前面已经排除了TCP_NAGLE_PUSH和TCP_NAGLE_CORK,Nagle的显式表示只有TCP_NAGLE_OFF,其余情况nonagle皆为0。
  2. tp->packets_out表示网络中的包,这是个强类型,当tp->packets_out为0时,网络中的包全部被确认,此时数据包需要立刻发送;当tp->packets_out>0,表明网络中存在数据包,使能TCP-Nagle。
  3. tcp_minshall_check(tp)是网络中仍存在小包,这是个弱类型,只要网络中没有小包,不管网络中是否还存在数据包未确认,都立即发送待发送的数据包;当网络中有小包时,则选择使能TCP-Nagle。

网络中有小包时,表明网络中必然有数据包;网络中无小包时,不管你有没有数据包,都立刻发送待发送的数据,所以,条件2是强类型(:更强的条件),条件3是弱类型。

对于大多数博客上说的delayACK和Nagle算法会导致时延增大,这点没有任何问题,但是黑盒方式的描述可能会让读者产生歧义,认为一个延迟的ACK是影响TCP-Nagle导致数据包滞后发送的原因。

实际上,TCP-Nagle在条件2、3上有解释,当接收所有的未确认报文或者是网络中不存在小包时,数据包会立刻发送。

这时,你可以这么理解,当对条件2、3判断时,可能会有多个延迟ACK的确认才会使得TCP-Nagle不使能,一个延迟ACK尚且有对数据包延迟有影响,当网络容量大时,多个延迟的ACK只会更加加重数据包的滞后,TCP-Nagle就变成了鸡肋。(TCP-Nagle是对网络中包的判断,并不是直接对ACK的判断)

结论

其实上,TCP-Nagle相比较于其他机制算是比较简单的,但纯粹的理论,或者说是黑盒,并不能解释的很通透,所以,对于白盒,我做了第一个,希望不是最后一个。

下面给出借鉴的博客:
1.https://blog.csdn.net/zhangskd/article/details/7712002?ops_request_misc=&request_id=&biz_id=102&utm_term=nagle%20zhangskd&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-7712002.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187

2.https://blog.csdn.net/wdscq1234/article/details/52432095?ops_request_misc=&request_id=&biz_id=102&utm_term=nagle算法&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-1-52432095.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187

3.https://blog.csdn.net/dog250/article/details/21303679?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164432001516780271977764%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164432001516780271977764&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-2-21303679.first_rank_v2_pc_rank_v29&utm_term=dog250+nagle算法&spm=1018.2226.3001.4187


http://chatgpt.dhexx.cn/article/fvNb1RVo.shtml

相关文章

Nagle算法原理与实现详解

文章目录 背景Nagle算法详解算法实现实现开启与关闭Nagle算法 Nagle算法与延迟ACK参考 背景 TCP的数据流大致可以被分成两类&#xff1a; 交互式数据流 TCP交互数据流指的是&#xff1a;TCP连接中传输的所有数据的总和&#xff0c;包括控制命令&#xff08;用于管理网络中连接…

TCP详解 (三)Nagle算法和延迟确认

文章目录 延迟确认Nagle算法Nagle算法遇上延迟确认关闭Nagle算法 一些有关TCP通信量的研究如[Caceresetal.1991]发现&#xff0c;如果按照分组数量计算&#xff0c;约有一半的TCP报文段包含成块数据&#xff08;如 FTP、电子邮件和 Usenet新闻&#xff09;&#xff0c;另一半则…

复指数信号正交性的简单证明

复指数信号为&#xff1a; . 写成矢量形式&#xff1a; 复指数信号两两正交&#xff0c;也就是两个复指数信号的内积有如下表示&#xff1a; 将上式内积形式展开&#xff1a; 当kl时&#xff0c;所有cos项1&#xff0c;sin项0&#xff0c;求和为N。 当时&#xff0c;将求和符…

三角函数正交性的推导

定理&#xff1a; 一个三角函数系&#xff1a;1 cosx sinx cos 一个三角函数系&#xff1a;1&#xff0c;cosx , sinx , cos2x , sin2x , … , cosnx , sinnx , … 如果这一堆函数&#xff08;包括常数1&#xff09;中任何两个不同函数的乘积在区间[-π, π]上的积分等于…

OFDM时频脉冲形状与子载波正交性的理解

从多载波调制的角度来理解子载波间正交&#xff0c;首先要明确OFDM默认的脉冲成型是时域矩形窗&#xff0c;时域上每个子载波 e j 2 π f n t e^{j2πf_nt} ej2πfn​t 都被一个矩形窗脉冲 g T ( t ) g_T(t) gT​(t)成型。其次&#xff0c;OFDM子载波间隔 等于 OFDM符号周期的…

正交性原理与维纳霍夫(正则)方程

有期望信号d&#xff08;n&#xff09;&#xff0c;纯净信号x&#xff08;n&#xff09;&#xff0c;以及噪声信号g&#xff08;n&#xff09;; 有滤波器h&#xff08;m&#xff09;,以及滤波器输出信号y&#xff08;n&#xff09;&#xff0c;滤波器输出纯净信号x的估计值y&a…

三大变换与自控(五)三角函数的正交性证明

在本系列文章的第一篇中&#xff0c;我们提到任何信号都可以被分解为三角函数&#xff0c;是因为三角函数的正交性&#xff0c;因此在三角函数构建的坐标系中可以绘制任何图形。现在我们就来证明一下三角函数的正交性&#xff0c;以完善我们整个推导过程。 教材上的三角函数系…

机器学习的数学基础(3):正交性原理(orthogonality principle)

思考这样一个问题&#xff0c;令S为一个希尔伯特空间&#xff0c;而空间S的一个子空间 当我们给定了&#xff0c;如何求最近上距离x最近的点。 则我们用数学语言表示该问题为一个优化问题&#xff1a; 该问题的解可以直接通过一个定理给出&#xff0c;即正交性定理&#xff0…

傅里叶级数与傅里叶变换_Part1_三角函数系的正交性

傅里叶级数与傅里叶变换_Part1_三角函数系的正交性 参考链接&#xff1a; DR_CAN老师的原视频 0、复习Part0的内容 参考链接&#xff1a;傅里叶级数与傅里叶变换_Part0_欧拉公式证明三角函数和差公式证明 三角函数的和差公式如下 sin ⁡ ( α β ) sin ⁡ ( α ) cos ⁡ …

09 正交性

09 正交性 9-1 空间&#xff0c;向量空间和欧几里得空间 9-2 广义向量空间 9-3 子空间 9-4 维度 9-5 行空间和矩阵的行秩 9-6 列空间 9-7 矩阵的秩和矩阵的逆 9-8 零空间与看待零空间的三个视角 9-9 零空间与秩-零化度定理 9-10 左零空间&#xff0c;四大子空间和研究子空间的…

CSS正交性分析

Refer: 为什么 CSS 这么难学&#xff1f; 我先来解释一下什么是正交。你调过显示器的「亮度」、「色调」和「饱和度」吧。 「亮度」就是明暗程度&#xff0c;值越大&#xff0c;屏幕越亮。 「色调」就是颜色&#xff0c;你通过调色调&#xff0c;可以把红色调成绿色。 「饱和度…

勒让德多项式的正交性和归一化

罗德里格斯公式正交性归一化应用 这学期上数学课时老师布置了一道习题&#xff1a;计算勒让德多项式的模。翻看本科数学物理方法教材&#xff0c;发现计算方法较复杂&#xff0c;且用到了生成函数 为了方便理清整个计算过程&#xff0c;这一博客直接从罗德里格斯公式出发并避免…

向量组的正交性

向量的内积定义 运算&#xff1a; 向量的正交性&#xff1a; 正交向量组的性质&#xff1a; 向量组的正交规范化 正交矩阵 定义&#xff1a; 正交矩阵的判定

拉盖尔多项式的正交性

标准拉盖尔多项式 拉盖尔多项式可以表示为&#xff1a; 拉盖尔多项式的正交性是指 当 时 上式的积分运算结果为0。这是一种加权的正交性。 证明&#xff1a; (1) 采用变换 容易得到,当 上式的结果为0是因为在进行微分运算后&#xff0c;各项均包含 , 各项的上下限均为0。 …

三角函数系的正交性

参考资料&#xff1a; https://zhuanlan.zhihu.com/p/341796771https://www.bilibili.com/video/BV1Et411R78v

1 三角函数的正交性

三角函数的正交性 三角函数的正交性三角函数系证明 三角函数的正交性 三角函数系 集合 { s i n 0 x , c o s 0 x , s i n x , c o s x , s i n 2 x , c o s 2 x , . . . } \lbrace sin0x, cos0x, sinx,cosx,sin2x,cos2x,... \rbrace {sin0x,cos0x,sinx,cosx,sin2x,cos2x,...…

正交的概念

“正交性”是从几何学中借来的术语。如果两条直线相交成直角&#xff0c;它们就是正交的&#xff0c;比如图中的坐标轴。用向量术语说&#xff0c;这两条直线互不依赖。沿着某一条直线移动&#xff0c;你投影到另一条直线上的位置不变。 在计算技术中&#xff0c;该术语用于表示…

正交性,从內积开始到施密特正交化

正交性 前言內积、长度和正交性[1]內积长度和距离正交向量非正交向量 正交集&#xff0c;正交基和正交投影正交集基定理1 正交基定理2 正交投影非零向量投影直线上的投影空间投影正交分解定理 格拉姆-施密特正交化参考 前言 多维空间&#xff0c;向量和矩阵&#xff0c;以及正…

三角函数正交性理解与Matlab分析

1.什么是正交性&#xff1f; “正交性”是从几何中借来的术语。如果两条直线相交成直角&#xff0c;他们就是正交的。在空间向量中&#xff0c;两个向量的标量积为零即两个向量正交。 如果两个函数满足&#xff0c;则称这两个函数正交。 2.什么是三角函数正交信号集&#xf…