3、TCP三次握手:过程详解与状态变迁
大家好,我是你们的老朋友。今天我们来聊聊TCP三次握手。
说实话,这个知识点几乎是每个网络工程师的必修课。面试必问,实战必用。我自己刚入行那会儿,觉得三次握手不就是“发三个包”嘛,有啥好学的?直到有一次线上排查连接超时问题,抓包一看,SYN包发出去对方没回,我才意识到——嗯,这里面的门道比我想象的多得多。
3.1 三次握手的过程详解
三次握手,说白了就是客户端和服务端互相确认“我准备好了,你呢?”的过程。我们一步步拆开看。
- 第一次握手:客户端发送SYN
客户端主动发起连接,发送一个SYN包(同步序列号)。这个包里带了一个初始序列号,比如
seq=x。此时客户端的状态变成SYN_SENT。 - 第二次握手:服务端回复SYN+ACK
服务端收到SYN后,如果同意建立连接,就回复一个SYN+ACK包。这个包里有两个关键信息:
seq=y(服务端的初始序列号)和ack=x+1(确认收到客户端的SYN)。服务端状态变成SYN_RCVD。 - 第三次握手:客户端发送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画了一张三次握手的流程图,方便你理解整个状态变迁。
这张图里,你可以清晰地看到三次消息交换和对应的状态变化。我个人建议你把这张图记在脑子里,面试时直接画出来,绝对加分。
3.5 常见问题与排查思路
在实际项目中,三次握手可能会遇到各种问题。我挑几个常见的说说。
- 连接超时:客户端发SYN后一直没收到SYN+ACK。可能原因:服务端没启动、防火墙拦截、网络不通。用
telnet或nc测试端口是否可达。 - 半连接队列满:服务端收到大量SYN但没完成三次握手,导致
SYN_RCVD状态的连接堆积。调整tcp_max_syn_backlog或启用tcp_syncookies。 - 连接被RST:服务端直接回复RST包。通常是因为端口没监听或防火墙主动拒绝。检查服务端进程是否正常运行。
一句话总结:三次握手是TCP可靠性的基石。它通过三次消息交换,确保双方都准备好后才开始传输数据。少了任何一次,都会留下隐患。
好了,关于三次握手的内容就到这里。记住,理解状态变迁比死记硬背更重要。下次你遇到连接问题,先想想握手过程,很多问题就能迎刃而解。