tcp三次握手耗时需通过tcpdump/wireshark抓包计算syn→syn-ack→ack时间差;ss -i查看内核rtt估算值判断网络质量;strace跟踪connect()获取总建连耗时;应用层埋点最精准,可区分建连、tls、服务端处理各阶段延迟。

tcpdump + Wireshark 分析三次握手耗时
Linux 本身不直接暴露每个连接的建立耗时(比如 SYN → SYN-ACK → ACK 各阶段时间戳),但可以通过抓包还原完整 TCP 握手过程,再手动或脚本计算时延。核心思路是捕获 SYN、SYN-ACK、ACK 三个包的时间戳,差值即为各阶段耗时。
实操建议:
在无 root/sudo 权限的环境(云容器、VPS、隔离主机)中安装并配置 OpenClaw 浏览器工具的 headless Chrome。适用场景:...
- 用
tcpdump -i any -w handshake.pcap 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0 and port 80'抓指定端口(如 80/443)的握手包,-i any确保不漏容器或虚拟网卡流量 - 抓完后用 Wireshark 打开,过滤
tcp.flags.syn == 1 || tcp.flags.ack == 1 and tcp.len == 0,定位三次握手三行;右键「Protocol Preferences → TCP → Calculate conversation timestamps」开启相对时间计算 - 注意:若服务端在 NAT 或负载均衡后(如 Nginx、AWS ALB),你抓到的
SYN-ACK可能来自中间设备而非真实后端,此时耗时反映的是链路+代理延迟,不是应用层真实建连时间
ss -i 显示重传与 RTT 估算值
ss -i 能读取内核为每个 socket 维护的 RTT(往返时间)估算值,虽非单次建连耗时,但对判断网络质量、是否因丢包导致握手慢很实用。
实操建议:
- 执行
ss -tien state established '( dport = :443 )' | head -5,查看 ESTABLISHED 连接的rtt:字段(单位微秒),例如rtt:124000/12000表示当前 RTT 估算是 124ms,RTTVAR 是 12ms - 该值由内核基于实际 ACK 延迟动态更新,若
rtt持续 > 300ms 或retrans列非 0,大概率存在链路丢包或中间设备限速 - 注意:
ss -i不显示握手阶段的初始 RTT,它只在连接建立后、有数据交互才开始收敛;新建连接刚完成握手时,这个值可能还是初始默认值(如 300ms)
strace 跟踪 connect() 系统调用耗时
如果目标是测量应用进程调用 connect() 到返回成功的总耗时(含 DNS、路由、握手全部环节),strace 是最贴近用户视角的方式。
实操建议:
- 运行
strace -T -e trace=connect,sendto,recvfrom curl -s http://example.com > /dev/null 2>&1,重点关注connect(…)行末尾的—— 这就是本次系统调用阻塞时间,即建连总耗时 - 若返回
-1 EINPROGRESS(非阻塞 socket),说明连接未立即完成,需配合poll()或select()等待,此时应跟踪后续getsockopt(SO_ERROR)是否成功来确认最终建连结果 - 注意:DNS 解析耗时会包含在
connect()内(若未预解析),若想排除 DNS 干扰,先用getent hosts example.com获取 IP,再用curl --resolve example.com:80:x.x.x.x强制跳过解析
应用层埋点比系统工具更准
所有系统级手段都有盲区:tcpdump 依赖抓包位置,ss 无单次粒度,strace 有性能开销且无法覆盖 setsockopt 参数影响(如 TCP_FASTOPEN)。真正要定位“为什么某个 HTTP 请求首字节慢”,必须在应用代码里打点。
实操建议:
- Go 用
net.Dialer.Deadline+time.Now()包裹DialContext;Python 用socket.create_connection(..., timeout=5)配合time.perf_counter() - 关键点:记录从调用开始、到
connect()返回成功、再到收到第一个响应字节的三个时间戳,才能区分是建连慢、TLS 握手慢,还是服务端处理慢 - 容易被忽略的是:某些语言 runtime(如 Node.js 的
net.connect)内部做了连接池复用,你看到的“建连耗时”可能是复用空闲连接,实际没走 TCP 握手 —— 此时必须结合ss -i或抓包验证 socket 是否真为新创建










