本文目录导读:

tcp_autocorking (内核参数 tcp_autocorking,通常由 net.ipv4.tcp_autocorking 控制) 本身没有独立的超时时间。
它不是一个定时器,而是一个延迟发送的决策机制,它的“超时”是依赖于 TCP 协议栈中已有的其他定时器(主要是 RTO - Retransmission Timeout,重传超时)来触发的。
tcp_autocorking 会阻止小包立即发送,等待更多数据填充,如果一直等不到足够的数据,它必须依靠某种机制“醒过来”把已有的数据发出去,这个“唤醒机制”就是RTO 定时器。
核心原理与流程
-
触发条件:
- 当应用层调用
send()写入一个小数据块(通常小于当前 MSS,即最大报文段大小)。 - 该 socket 启用了
tcp_autocorking(通常默认开启,Linux 3.18+)。 - 关键前提:该 socket 当前已经有未确认的数据在重传队列中(即前面已经发过包,但还没收到 ACK,正处于“Flight”状态)。
- 当应用层调用
-
动作:
- 内核不会立即把这段小数据打包发送。
- 它会将数据缓存起来,等待应用层下一次
send()调用,以期凑够一个完整的 MSS 或者打到其他发送条件。
-
超时与唤醒:
- 如果应用层再也不发数据了,或者发得极慢,这段缓存的小数据就会一直待在发送缓冲区里。
- 这时,RTO 定时器登场:
- 前面提到,触发
tcp_autocorking的前提是重传队列非空,重传队列中的报文本身带有一个 RTO 定时器。 - 当这个 RTO 定时器超时时,内核会调用
tcp_write_timer_handler()。 - 在这个处理函数中,内核会检查是否因为
autocorking导致数据被卡住,如果发现是因为autocorking正在等待数据,而 RTO 已经超时,内核会强制“解开” corking:- 它会将
icsk->icsk_ack.pending和icsk->icsk_ack.pingpong等状态重置。 - 然后调用
tcp_write_xmit()或__tcp_push_pending_frames()将所有累积的数据立即发送出去。
- 它会将
- 换句话说,
autocorking的“超时”时间就是当前连接重传队列中某个数据包的 RTO 值。
- 前面提到,触发
直接影响因素
tcp_autocorking 的“延迟时间”(即从数据被 cork 到最终被发送的时长)主要由以下几个因素决定:
-
RTO 的计算值:RTO 不是固定的,它由 TCP 的 RTT(往返时间)测量和 SRTT(平滑往返时间)算法动态计算,通常初始 RTO 在 1 秒左右,但会随网络状况变化。
- 如果网络状况好,RTT 小,RTO 也小,
autocorking延迟就短。 - 如果网络丢包或延迟大,RTO 会指数退避(翻倍增长),
autocorking延迟会急剧增加(可能达到几十秒)。
- 如果网络状况好,RTT 小,RTO 也小,
-
是否存在重传队列:如果连接刚建立,还未发送过任何数据(重传队列为空),
tcp_autocorking不会生效,小包会立即发送。只有重传队列非空时,autocorking才会被触发。 -
是否 ping-pong 模式:
tcp_autocorking的代码逻辑会检查icsk->icsk_ack.pingpong标志,如果应用层是交互式、请求-响应模式(如 SSH),autocorking会被抑制,不会延迟小包。
具体代码中的体现
在 Linux 内核源码 net/ipv4/tcp_output.c 的 tcp_small_queue_check() 和 tcp_sendmsg() 中可以看到逻辑:
// 简化逻辑
bool tcp_autocorking(struct sock *sk)
{
return (sock_flag(sk, SOCK_CORK) == false) &&
(sk->sk_route_caps & NETIF_F_SG) &&
(tcp_sk(sk)->tcp_autocorking) &&
/* 关键条件:重传队列非空 */
(tcp_sk(sk)->retransmits < sysctl_tcp_retries1) &&
(sk_stream_mem_free(sk) > 0) &&
/* pingpong 模式会跳过 */
(tcp_sk(sk)->icsk_ack.pingpong == 0);
}
而在 tcp_write_timer() 中:
static void tcp_write_timer(struct sock *sk, ...)
{
// ... RTO 超时处理 ...
tcp_write_timer_handler(sk);
}
void tcp_write_timer_handler(struct sock *sk)
{
// ... 进行重传 ...
// 如果发现有因 autocorking 而缓存的数据,会强制发送
if (sk->sk_send_head) {
tcp_write_xmit(sk, ...);
}
}
| 特性 | 说明 |
|---|---|
tcp_autocorking 的“超时时间” |
不固定,等于当前连接重传队列中最旧数据包的 RTO 值。 |
| 如何发生超时 | 依赖 RTO 定时器,当 RTO 到期,内核在处理重传的同时,会检查并强制发送 autocorking 缓存的报文。 |
| 典型延迟范围 | 初始 RTO 约 1 秒,但在丢包或网络抖动时,RTO 会指数退避(1s -> 2s -> 4s ...),autocorking 延迟可能非常长。 |
| 如何避免长延迟 | 对于交互式应用(如 SSH、游戏),pingpong 标志会抑制 autocorking,小包不被延迟,对于需要低延迟的应用,可以关闭 tcp_autocorking(net.ipv4.tcp_autocorking = 0)。 |
核心结论:tcp_autocorking 没有自己的超时,它借用了RTO 定时器来“唤醒”并发送缓存数据,它的延迟动态取决于网络质量和 RTT。