AIGC标识 TCP 三次握手慢在哪?用 Python 算连接建立时间

TCP 三次握手慢在哪?用 Python 算连接建立时间

做网络层调试时,响应慢往往不是因为带宽不够,而是连接建立阶段就花了太多时间。这篇用 Python socket 直接测 TCP 握手耗时,看看到底慢在哪一步。

为什么用 socket 测,而不是直接 ping

ping 测的是 ICMP 往返延迟,不代表 TCP 握手时间。TCP 握手除了网络延迟,还要算上目标站处理 SYN 请求、端口是否开放、中间设备有没有拦截等因素。所以要看连接建立时间,最准的就是自己发一个 TCP 连接,从 connect() 开始到成功为止计时。

socket.connect() 返回的时候,三次握手已经完成了。我们测的就是这个过程的总耗时。

三次握手哪一步最耗时

简化理解:

  • 第一次:客户端发 SYN
  • 第二次:服务端回 SYN-ACK
  • 第三次:客户端回 ACK

网络延迟主要消耗在第一步到第二步之间,也就是 SYN 发出去到收到 SYN-ACK 这段时间。因为这段要经过路由、防火墙、运营商网络,往返一次就是一个 RTT。第三步 ACK 通常可以和第一个数据包合并,耗时相对少。

所以 handshake 时间 ≈ 一个 RTT,再加上服务端处理 SYN 的时间。

一段可跑的脚本

import socket
import time

def tcp_handshake(host, port=443, timeout=5):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(timeout)
    t0 = time.time()
    try:
        s.connect((host, port))
        return time.time() - t0
    finally:
        s.close()

hosts = ["baidu.com", "github.com", "cloudflare.com"]
for h in hosts:
    try:
        cost = tcp_handshake(h, 443)
        print(f"{h}: {cost * 1000:.1f}ms")
    except Exception as e:
        print(f"{h}: {type(e).__name__}")

运行结果大概长这样:

baidu.com: 99.9ms
github.com: TimeoutError
cloudflare.com: 219.2ms

不同网络环境结果会差很多。GitHub 超时是因为我当前环境连它不通,不代表你的环境也这样。可以把 hosts 列表换成你日常要访问的接口域名。

结果怎么看

  • 几十毫秒以内:握手很快,网络延迟和服务端响应都正常。
  • 几百毫秒:网络延迟较高,或者服务端处理 SYN 较慢。
  • 超时或连接拒绝:端口没开、防火墙拦截、网络不通、或者目标站限流。

如果同一个域名连续测几次波动很大,说明网络抖动明显;如果每次都稳定在一个较高值,说明就是物理距离或路由绕路。

什么情况下握手会变慢

我实际遇到过的几种情况:

  • DNS 解析后拿到一个很远或很烂的 IP:虽然握手代码里直接是 IP 或域名,但域名会先解析。如果 DNS 给了你一个海外 CDN 节点,握手时间就上去了。
  • 中间防火墙对新建连接做审查:有些企业网络或地区网关会对 outbound TCP 连接做检测,第一次 SYN 会被延迟处理。
  • 目标端口不是标准端口:比如 443 和 8080 的待遇可能不一样,有些防火墙对非常用端口会额外丢包或限流。
  • 服务端 SYN 队列满了:高并发场景下,服务端 backlog 满了会丢弃或延迟 SYN-ACK,握手时间也会变长。

再精确一点:拆分 SYN 和 SYN-ACK

socket 的 connect() 只能测总握手时间。如果想单独看 SYN 到 SYN-ACK 这段,就需要用 raw socket 自己构造 SYN 包。但 raw socket 在 Windows 上需要管理员权限,跨平台也麻烦,日常调试我不怎么用。

大多数业务场景下,connect() 的耗时已经够用了。只有在做网络层深度分析时,我才会上抓包工具看具体每一步的毫秒数。

我的使用习惯

  • 接口响应慢,先不怀疑业务代码,用这段脚本测一下握手时间。
  • handshake 时间长,就去看 DNS 解析结果和路由。
  • handshake 时间正常但请求慢,问题在应用层或读取响应阶段。
  • 做压测前,我会先批量测一批目标域名的握手时间,筛掉明显不稳定的。

参考


posted @ 2026-08-07 15:34  IP观察室  阅读(3)  评论(0)    收藏  举报