必须先确认内核≥3.7且tcp_fastopen=3,否则配置无效;服务端需应用层调用setsockopt启用tfo队列(如nginx加fastopen=256),客户端须用msg_fastopen或curl --tcp-fastopen触发,ss -i验证tfo标记、tcpdump抓包确认syn含cookie才算生效。

必须先确认内核支持且 tcp_fastopen 值设为 3,否则后续所有配置都无效。
检查内核版本和当前 TFO 状态
运行 uname -r,确保输出 ≥ 3.7(服务端建议 ≥ 4.1);再执行 cat /proc/sys/net/ipv4/tcp_fastopen:
- 返回
0:TFO 完全禁用,需手动开启 - 返回
1:仅客户端可用,服务端不响应 TFO 请求 - 返回
2:仅服务端接受 TFO 连接,但客户端无法发起 - 返回
3:双向启用,是生产环境推荐值
若非 3,临时启用: echo 3 > /proc/sys/net/ipv4/tcp_fastopen(需 root)
永久生效并避免 systemd-sysctl 延迟加载
编辑 /etc/sysctl.conf,添加一行:net.ipv4.tcp_fastopen = 3。然后执行 sysctl -p 加载。
但注意:CentOS 7 或旧版 systemd 可能延迟应用该值——必须额外执行:systemctl restart systemd-sysctl,否则重启后仍为 0。
验证是否真正生效:sysctl net.ipv4.tcp_fastopen 和 cat /proc/sys/net/ipv4/tcp_fastopen 输出必须一致且为 3。
服务端应用必须显式启用监听 socket 的 TFO 队列
内核开关只是基础,Nginx、OpenResty 或自研服务若未在 listen socket 上调用 setsockopt(, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)),客户端发来的 SYN-data 会被静默丢弃。
-
Nginx ≥ 1.15.5:在listen指令后加fastopen=256(如listen 443 ssl http2 fastopen=256;) - 自研 C/C++ 服务:必须在
bind()后、listen()前调用setsockopt(),qlen建议设为5–128(并发高时可设更大) - Go 程序(≥ 1.13):需使用
golang.org/x/net/tcp包,并设置TCPFastOpen: true
验证服务端是否就绪:ss -i | grep :443(替换为你监听的端口),输出中出现 tfo:0x1 才表示已启用。
客户端触发 TFO 必须用 sendto() + MSG_FASTOPEN
传统 connect() → send() 流程不会触发 TFO,首次连接也必然走完整三次握手(只为获取 Cookie)。
- C/C++ 客户端:创建 socket 后,直接调用
sendto(sockfd, data, len, MSG_FASTOPEN, ...);glibc ≥ 2.23才支持MSG_FASTOPEN -
curl ≥ 7.49.0:用curl --tcp-fastopen https://example.com即可自动处理 Cookie 缓存与重试 - 压测时务必复用 client IP 和端口(如
wrk -t4 -c100 -d30s --tcp-fastopen),否则每次都是“首次连接”,永远看不到 RTT 节省
抓包验证是否真正生效:用 tcpdump 抓到 SYN 包长度 > 60 字节,且 Wireshark 中 TCP Options 里含 TFO Cookie 字段,才算走通整条链路。
最容易被忽略的是:服务端没配 fastopen= 或客户端没用 MSG_FASTOPEN —— 此时即使 /proc/sys/net/ipv4/tcp_fastopen 显示为 3,TFO 也完全不工作。











