打开抓包软件再访问一个网站,最前面三条记录永远是 SYN、SYN ACK、ACK,然后才轮到 HTTP 请求出场。这三步就是 tcp三次握手,走完它,双方才算真正把连接搭起来。

三步各自在干什么

  • 第一步:客户端发 SYN 包,带上一个随机初始序号,自己进入 SYN_SENT 状态
  • 第二步:服务器回 SYN 加 ACK,确认号在对方序号上加一,自己进入 SYN_RCVD 状态
  • 第三步:客户端回 ACK,双方进入 ESTABLISHED,开始传数据

初始序号是随机生成的,这一点很关键:网络里会滞留上一次连接的残留包,随机序号能让新旧连接的数据对不上号,旧的包直接被丢弃,不会混进现在的对话里。

为什么两次不够

握手的本质是确认双方的发送和接收能力都正常。只握两次就开连接,一个在网络里迟到很久的旧 SYN 到达后,服务器会白白开一条连接傻等数据,这种半开连接积累起来全是浪费;有了第三次 ACK,旧包引发的建立流程走不完,资源不会被占住。

顺带认识几个状态

排查连接问题时 netstat -an 里常见几个值:大量 SYN_SENT 说明本机发出去的连接没人应答,对方端口不通或被防火墙拦了;服务端大量 SYN_RCVD 堆着,是 SYN Flood 攻击的典型特征——只发 SYN 不回 ACK,把半连接队列塞满,防火墙一般都有对应的防护项。握手一来一回的时间也决定着首字节延迟,抓包时看 RTT 就能估个大概。

抓包时还能顺便看 RTT,握手一来一回的时间差不多就是连接建立的下限。HTTPS 网站在握手完成后还要走一遍 TLS 握手,层数比纯 HTTP 多,排查打开慢的时候要分清是 TCP 建连慢还是 TLS 协商慢。

挂断的时候是四次挥手,因为接收方可能还有数据没发完,ACK 和 FIN 分开先后发,比握手多一步。主动关闭的一方最后会停在 TIME_WAIT 状态等一阵,确保最后的 ACK 送达对方,端口回收慢一点属正常现象,不是故障。先看握手成没成,再看重传和谁先发 FIN,连接类问题的排查就有章法了。