tcpdump + tshark 可精确提取三次握手耗时:先用 tcpdump 抓包,再用 tshark 按 tcp.stream 分组提取 SYN、SYN-ACK、ACK 时间戳并计算差值,从而获得毫秒级握手延迟分布。

tcpdump + tshark 能直接提取三次握手耗时
Linux 没有现成命令一键输出“SYN→SYN-ACK→ACK”的毫秒级分布,但 tcpdump 抓包后用 tshark 可精确计算每个连接的握手延迟。关键不是看连接是否存在,而是看每个 TCP 流中三个关键报文的时间戳差。
- 先用
tcpdump -i eth0 -w handshake.pcap port 80 or port 443抓指定端口流量(替换eth0为实际网卡) - 再用
tshark -r handshake.pcap -T fields -e frame.time_epoch -e tcp.seq -e tcp.ack -e tcp.flags.syn -e tcp.flags.ack -e ip.src -e ip.dst提取原始时间戳和标志位 - 真正要的是每个流首次出现
SYN=1, ACK=0、SYN=1, ACK=1、SYN=0, ACK=1的三条记录,按ip.src+ip.dst+tcp.seq(或tcp.stream)分组后算时间差
用 tshark 自动计算 handshake_time(推荐)
tshark 从 3.6+ 版本起内置了 tcp.time_delta 和流状态字段,可直接导出握手耗时,避免手写解析逻辑:
- 运行:
tshark -r handshake.pcap -Y "tcp.flags.syn == 1 and (tcp.flags.ack == 0 || tcp.flags.ack == 1)" -T fields -e tcp.stream -e frame.time_epoch -e tcp.flags.syn -e tcp.flags.ack | sort -n -k1,1 - 再用 awk 按 stream 分组,取第 1 行(SYN)、第 2 行(SYN-ACK)、第 3 行(ACK)对应时间戳相减:SYN-ACK 减 SYN 得客户端到服务端 RTT 估算,ACK 减 SYN-ACK 得服务端处理延迟
- 注意:若抓包点在客户端侧,
SYN→SYN-ACK时间包含网络往返 + 服务端内核协议栈处理;若在服务端侧,该值更接近纯网络延迟
ss -i 显示单连接的重传与 rtt,但不反映握手分布
ss -i 只能查已建立连接的当前 rtt 和 rttvar,它来自内核 TCP 拥塞控制模块维护的平滑 RTT 估计值,不是真实握手耗时,也不提供历史分布:
-
ss -tien state established '( dport = :443 )'输出里rtt:12345/678表示当前 smoothed RTT ≈ 12.345ms,偏差 ±0.678ms - 这个值会随后续数据包持续更新,和三次握手那一刻的延迟可能差几毫秒甚至几十毫秒
- 无法区分是网络抖动导致还是服务端 accept() 延迟高——它把整个连接生命周期的延迟混在一起了
别用 curl -w 或 httpie 测“握手时间”,它们测的是 TLS 握手+HTTP 发起总耗时
很多人误以为 curl -w "%{time_connect}" 返回的就是 TCP 握手时间,其实不是:
-
time_connect是从 DNS 解析结束到收到第一个 HTTP 响应头之间的时间,中间包含 TCP 握手 + TLS 握手(如果用了 HTTPS)+ HTTP 请求发送 + 等待响应头 - 即使加
--no-ssl,它仍包含内核 connect() 系统调用返回时间,而该调用返回 ≠ ACK 收到,取决于 socket 是否设为非阻塞、是否有超时等 - 真正想分析网络层握手瓶颈,必须回到数据包层面;应用层工具只适合做端到端可观测性基线,不能替代链路诊断
抓包分析看似麻烦,但只有 tcpdump + tshark 能告诉你:到底是 SYN 卡在防火墙、SYN-ACK 被丢弃,还是 ACK 回得慢——这些细节在统计分布图里一目了然,而其他方法全会掩盖掉。


















