3、TCP三次握手:过程详解与状态变迁

大家好,我是你们的老朋友。今天我们来聊聊TCP三次握手。

说实话,这个知识点几乎是每个网络工程师的必修课。面试必问,实战必用。我自己刚入行那会儿,觉得三次握手不就是“发三个包”嘛,有啥好学的?直到有一次线上排查连接超时问题,抓包一看,SYN包发出去对方没回,我才意识到——嗯,这里面的门道比我想象的多得多。

3.1 三次握手的过程详解

三次握手,说白了就是客户端和服务端互相确认“我准备好了,你呢?”的过程。我们一步步拆开看。

  1. 第一次握手:客户端发送SYN

    客户端主动发起连接,发送一个SYN包(同步序列号)。这个包里带了一个初始序列号,比如 seq=x。此时客户端的状态变成 SYN_SENT。

  2. 第二次握手:服务端回复SYN+ACK

    服务端收到SYN后,如果同意建立连接,就回复一个SYN+ACK包。这个包里有两个关键信息:seq=y(服务端的初始序列号)和 ack=x+1(确认收到客户端的SYN)。服务端状态变成 SYN_RCVD。

  3. 第三次握手:客户端发送ACK

    客户端收到SYN+ACK后,再发一个ACK包,seq=x+1,ack=y+1。这个包发出去后,客户端状态变成 ESTABLISHED。服务端收到这个ACK后,也变成 ESTABLISHED。

你看,整个过程就是三次消息交换。我习惯把这三步记成“你问—我答—你确认”。简单吧?

核心要点:三次握手的本质是双方各自确认对方的接收能力和发送能力都正常。

3.2 状态变迁详解

TCP连接的状态变化,就像一个人的情绪变化。我们来看看每个状态是怎么流转的。

状态 含义 出现时机
CLOSED 初始状态,没有连接 连接未建立或已关闭
SYN_SENT 客户端已发送SYN 第一次握手后
SYN_RCVD 服务端已收到SYN并回复SYN+ACK 第二次握手后
ESTABLISHED 连接已建立,可以传输数据 第三次握手完成后

我举个例子。你在浏览器里输入一个网址,浏览器作为客户端,会经历 CLOSED → SYN_SENT → ESTABLISHED。而服务器那边则是 CLOSED → SYN_RCVD → ESTABLISHED。

有一次我在排查一个服务端连接数过高的问题,发现很多连接卡在 SYN_RCVD 状态。一查,原来是客户端发了SYN后没发第三次ACK。这就是典型的半连接攻击。嗯,这里要小心。

避坑指南:我曾经遇到过线上服务大量连接处于 SYN_RCVD 状态,导致新连接无法建立。后来通过调整 tcp_synack_retries 和启用 tcp_syncookies 解决了。如果你也遇到类似问题,不妨先看看这个。

3.3 为什么是三次而不是两次?

这个问题我面试过很多人,也被人面试过。你想想看,如果只用两次握手会怎样?

假设只有两次握手:客户端发SYN,服务端回SYN+ACK,然后服务端就认为连接建立了。但客户端可能因为网络延迟,根本没收到这个SYN+ACK。这时候服务端傻傻地等着客户端发数据,而客户端还在重传SYN。结果就是服务端白白浪费资源。

更严重的情况是:客户端发了一个SYN,因为网络拥堵,这个SYN延迟了很久才到达服务端。服务端回复SYN+ACK后认为连接建立,但客户端早就放弃了。服务端就一直在那等着,直到超时。这就是资源浪费。

三次握手解决了这个问题。客户端收到SYN+ACK后,再发一次ACK,服务端才知道“哦,客户端确实收到了我的回复”。说白了,三次握手是为了防止“已失效的连接请求”到达服务端后,服务端误以为是一个新的连接请求。

个人经验:我建议你在设计高并发服务时,一定要考虑三次握手带来的延迟。每次握手至少需要一个RTT(往返时间)。如果客户端和服务端物理距离很远,这个延迟会很明显。我曾经优化过一个跨国业务,就是通过减少握手次数来提升用户体验的。

3.4 核心流程图

下面我用SVG画了一张三次握手的流程图,方便你理解整个状态变迁。

客户端 服务端 CLOSED CLOSED SYN (seq=x) SYN_SENT SYN+ACK (seq=y, ack=x+1) SYN_RCVD ACK (seq=x+1, ack=y+1) ESTABLISHED ESTABLISHED

这张图里,你可以清晰地看到三次消息交换和对应的状态变化。我个人建议你把这张图记在脑子里,面试时直接画出来,绝对加分。

3.5 常见问题与排查思路

在实际项目中,三次握手可能会遇到各种问题。我挑几个常见的说说。

  • 连接超时:客户端发SYN后一直没收到SYN+ACK。可能原因:服务端没启动、防火墙拦截、网络不通。用 telnet 或 nc 测试端口是否可达。
  • 半连接队列满:服务端收到大量SYN但没完成三次握手,导致 SYN_RCVD 状态的连接堆积。调整 tcp_max_syn_backlog 或启用 tcp_syncookies。
  • 连接被RST:服务端直接回复RST包。通常是因为端口没监听或防火墙主动拒绝。检查服务端进程是否正常运行。

一句话总结:三次握手是TCP可靠性的基石。它通过三次消息交换,确保双方都准备好后才开始传输数据。少了任何一次,都会留下隐患。

好了,关于三次握手的内容就到这里。记住,理解状态变迁比死记硬背更重要。下次你遇到连接问题,先想想握手过程,很多问题就能迎刃而解。

可可精品资料库