面试高频考点:深入解析 TCP 三次握手与四次挥手原理
TCP 协议是互联网通信的核心基础,其可靠性机制通过三次握手建立连接、四次挥手释放连接来实现。在技术面试中,这部分内容属于必考的基础题,往往也是区分候选人对底层网络理解深度的关键。很多开发者虽然知道流程,但在面对状态变迁、队列机制及异常处理时容易回答不完整。
本文将系统梳理 TCP 连接的建立与断开过程,涵盖状态机变化、序列号同步、半连接队列机制、SYN 攻击防御以及 TIME_WAIT 状态的优化策略,帮助读者构建完整的知识体系。
1. 三次握手详解
三次握手(Three-way Handshake)是指在建立 TCP 连接时,客户端和服务器总共需要交换三个报文段。其主要目的是确认双方的接收能力和发送能力是否正常,并初始化序列号(ISN),为后续的数据可靠传输做准备。实质上,这是连接指定端口、同步双方序列号和确认号、交换窗口大小的过程。
初始状态下,客户端处于 Closed 状态,服务端处于 Listen 状态。
1.1 握手流程
第一次握手: 客户端向服务端发送一个 SYN 报文,指明客户端的初始化序列号 ISN(x)。此时客户端进入 SYN_SEND 状态。
- 首部标志位:SYN=1
- 初始序号:seq=x
- 说明:SYN=1 的报文段不能携带数据,但要消耗掉一个序号。
第二次握手: 服务端收到客户端的 SYN 报文后,会以自己的 SYN 报文作为应答,同时指定自己的初始化序列号 ISN(y)。并将客户端的 ISN + 1 作为 ACK 的值,表示已收到客户端的 SYN。此时服务端进入 SYN_RECV 状态。
- 首部标志位:SYN=1, ACK=1
- 确认号:ack=x+1
- 初始序号:seq=y
第三次握手: 客户端收到服务端的 SYN 报文后,发送一个 ACK 报文,将服务器的 ISN + 1 作为 ACK 的值,表示已收到服务端的 SYN。此时客户端进入 ESTABLISHED 状态。服务端收到 ACK 后也进入 ESTABLISHED 状态,连接正式建立。
- 首部标志位:ACK=1
- 确认号:ack=y+1
- 序号:seq=x+1
- 说明:ACK 报文段可以携带数据,不携带数据则不消耗序号。
在 Socket 编程中,客户端执行 connect() 操作时会触发三次握手。
1.2 为什么需要三次握手?
两次握手无法解决'已失效的连接请求'问题。如果只有两次握手:
- 客户端发出连接请求,因丢失未收到确认,重传一次请求。服务端收到确认,建立连接。
- 第一个丢失的请求在网络节点滞留,延误到连接释放后才到达服务端。
- 服务端误认为是新请求,同意建立连接,但客户端忽略该确认且不发送数据。
- 服务端一直等待客户端发送数据,浪费资源。
三次握手确保了服务端能确认客户端的接收能力正常,避免了上述死锁和资源浪费情况。
1.3 半连接队列与全连接队列
半连接队列(Syn Queue): 服务器收到客户端 SYN 后,处于 SYN_RECV 状态,此时连接尚未完全建立。服务器将此类请求放入半连接队列。
全连接队列(Accept Queue):
完成三次握手后,连接进入 ESTABLISHED 状态,被放入全连接队列等待应用层调用 accept() 获取。
若队列满,可能导致丢包或拒绝新连接。系统参数如 net.ipv4.tcp_max_syn_backlog 可控制半连接队列长度。此外,SYN-ACK 重传次数有限制,默认通常为 5 次,超时后从半连接队列删除。
1.4 ISN 是否固定?
ISN(Initial Sequence Number)不是固定的。它随时间动态变化,通常每 4ms 加 1。这样设计的目的是防止在网络中延迟的旧分组在连接结束后再次到达,导致接收方错误解释数据。如果 ISN 固定,攻击者容易猜出后续确认号,进行欺骗攻击。
1.5 握手过程中可以携带数据吗?
- 第一次、第二次握手: 不可以携带数据。因为此时连接尚未完全建立,且为了防止 SYN Flood 攻击,避免服务器分配过多资源处理无效数据。
- 可以携带数据。此时客户端已处于 ESTABLISHED 状态,确认了双方收发能力正常,携带数据不会增加安全风险。


