tcp报文什么时候会真正发送

当用户使用tcp socket发送数据时,数据会立即被发送吗?不一定,tcp报文真正的发送由内核来定。那么满足什么条件的时候,tcp报文才会真正被发送?

用户调用tcp socket的send函数,在内核调用tcp_sendmsg进入tcp协议栈,tcp协议栈的出口是tcp_transmit_skb,通过该函数将报文发送给ip层。

讨论tcp报文什么时候会真正发送,先看一下有哪些条件会导致tcp报文不会被发送,当这些条件都不满足的时候,那么tcp就会被真正发送。本文只列出一个典型的环节,tcp协议栈的具体实现要复杂的多。

autocroking

自动软木塞,在满足某些条件时,数据不会被立即发送,而是在缓冲区缓存。

/* If a not yet filled skb is pushed, do not send it if

* we have data packets in Qdisc or NIC queues :

* Because TX completion will happen shortly, it gives a chance

* to coalesce future sendmsg() payload into this skb, without

* need for a timer, and with no latency trade off.

* As packets containing data payload have a bigger truesize

* than pure acks (dataless) packets, the last checks prevent

* autocorking if we only have an ACK in Qdisc/NIC queues,

* or if TX completion was delayed after we processed ACK packet.

*/

static bool tcp_should_autocork(struct sock *sk, struct sk_buff *skb,

int size_goal)

{

return skb->len < size_goal &&

READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_autocorking) &&

!tcp_rtx_queue_empty(sk) &&

refcount_read(&sk->sk_wmem_alloc) > skb->truesize &&

tcp_skb_can_collapse_to(skb);

}

这个条件判断的比较谨慎,只有4个条件都满足时,才不会立即发送。

(1)数据的长度小于size goal,还没有达到目标,先不发送。size goal是基于mss和gso计算出来的,一般比mss要大。

(2)autocorking使能,我感觉这个条件应该作为第一个条件,这个功能的开关。

(3)sk->sk_wmem_alloc每向下层队列发送,则会增加;发送完成,则会减少。该条件满足,说明在底层队列中还有数据没有发送。

(4)当前这个skb还有一些空间没有使用,还可以追加一些数据,这个时候,可以不发送

tsq tasklet

被autocorkong限流的报文什么时候会真正发送?通过tsq tasklet发送,如下代码所示,当对socket进行限流时,会设置一个标记TSQ_THROTTLED。

if (tcp_should_autocork(sk, skb, size_goal)) {

/* avoid atomic op if TSQ_THROTTLED bit is already set */

if (!test_bit(TSQ_THROTTLED, &sk->sk_tsq_flags)) {

NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAUTOCORKING);

set_bit(TSQ_THROTTLED, &sk->sk_tsq_flags);

}

/* It is possible TX completion already happened

* before we set TSQ_THROTTLED.

*/

if (refcount_read(&sk->sk_wmem_alloc) > skb->truesize)

return;

}

当报文从底层队列中发走并释放skb时,会调用函数tcp_wfree,在该函数中会调度tsq_tasklet,最后发送socket中的数据。

tsq全称为tcp small queue,避免在底层队列中有太多的小包,在autocorking中做的事情和在函数tcp_small_queue_check中做的事情是相似的。

tasklet是小任务,linux中任务延后执行的机制有软中断、tasklet。延后执行的机制,在应用开发中也常用到,比如线程池,可以延后处理任务。

拥塞窗口和发送窗口

拥塞窗口主要看已经发送还没有确认的报文数量,如果这些报文的数量大于拥塞窗口,则不发送。

发送窗口看要发送的数据是不是超过了发送窗口的大小,如果是,则不发送。

发送窗口由接收侧控制,在tcp建立连接的过程中会根据初始条件确定发送窗口的大小,

拥塞窗口:慢启动,拥塞避免,拥塞处理

发送窗口:由接收窗口决定

nagle

收到ack的时候

重传

定时机制

用户控制

相关推荐
ZFSS5 小时前
Localization Translate API 集成与使用指南
java·服务器·数据库·人工智能·mysql·ai编程
TechWayfarer5 小时前
查询IP所在地的3种方案:从API到离线库,风控场景怎么选?
开发语言·网络·python·网络协议·tcp/ip
索木木7 小时前
NCCL SHARP 和 TREE算法
java·服务器·算法
ylscode8 小时前
微软Exchange Server曝高危零日漏洞:朝鲜黑客利用“Toast攻击“入侵企业邮件系统
网络·安全·web安全
Bert.Cai8 小时前
Linux let命令详解
linux·运维·服务器
晚风予卿云月8 小时前
【Linux】环境变量概念、作用、配置与修改详解
linux·运维·服务器·环境变量
heimeiyingwang8 小时前
【架构实战】可观测性体系:从监控到全链路追踪
网络·数据库·架构
benjiangliu8 小时前
LINUX系统-17-EXT系列文件系统(二)
linux·运维·服务器
杨云龙UP8 小时前
Linux 根分区被日志吃满?一次 58G Broker 日志清理实战_2026-05-20
linux·运维·服务器·数据库·hdfs·apache
ㄣ知冷煖★9 小时前
统一网关架构实践:从 Token 鉴权到路由、策略与凭证池转发全链路解析
java·服务器·架构