TCP 三次握手 / 四次挥手 讲解

TCP(传输控制协议)的三次握手是建立可靠连接的基础。虽然你之前问的是词语,但这个问题很经典,我直接给你讲清楚:


三次握手的过程

步骤 发起方 动作 发送内容 接收方状态
第一次 客户端 → 发送 SYN=1,Seq=x(随机初始序列号) 服务端收到,知道客户端想建立连接
第二次 服务端 → 回复 SYN=1,ACK=1,Seq=y,Ack=x+1 客户端收到,知道服务端已收到自己的请求
第三次 客户端 → 确认 ACK=1,Seq=x+1,Ack=y+1 服务端收到,连接正式建立

通俗比喻(打电话)

  1. 客户端:"喂,能听到吗?"(SYN)

  2. 服务端:"听到了,你能听到我吗?"(SYN+ACK)

  3. 客户端:"听到了,开始说吧。"(ACK)


为什么要三次,而不是两次?

核心目的:确认双方的收发能力都正常

  • 第一次 :服务端确认客户端的发送能力正常

  • 第二次 :客户端确认服务端的接收+发送能力都正常

  • 第三次 :服务端确认客户端的接收能力也正常

如果只有两次握手,服务端无法确认客户端是否真的收到了自己的SYN-ACK回复,可能会造成已失效的连接请求报文段 突然传到服务端,导致资源浪费(这就是经典的已失效连接请求报文段问题)。


常见面试追问

Q:第三次握手可以携带数据吗?

A: 可以,但一般不建议。因为此时连接尚未完全建立,如果携带数据,服务端收到后必须先缓存,等连接建立再处理,增加开销。
Q:如果第三次握手丢了怎么办?

A: 服务端会重发SYN-ACK(超时重传),如果多次重传仍收不到ACK,服务端会关闭连接,释放资源。

四次挥手

一、四次挥手的过程(断开连接)

步骤 发起方 动作 发送内容 含义
第一次 主动关闭方(通常是客户端) → 发送 FIN=1,Seq=u "我没数据要发了,想关闭连接"
第二次 被动关闭方(通常是服务端) → 回复 ACK=1,Seq=v,Ack=u+1 "收到你的关闭请求,但我可能还有数据要发"
第三次 被动关闭方 → 发送 FIN=1,Seq=w,Ack=u+1 "我的数据也发完了,可以关闭了"
第四次 主动关闭方 → 回复 ACK=1,Seq=u+1,Ack=w+1 "收到,确认关闭"

注意:第二次和第三次之间,被动关闭方可能还会继续发送数据,这就是**半关闭(half-close)**状态。


二、通俗比喻(挂电话)

  1. 客户端:"我说完了,先挂了。"(FIN)

  2. 服务端:"好的,收到。"(ACK)------但服务端可能还有话没说完

  3. 服务端(说完后):"我也说完了,挂了吧。"(FIN)

  4. 客户端:"好,拜拜。"(ACK)------然后客户端等一会儿再真正挂断


三、为什么是四次,而不是三次?

因为 TCP 是全双工(双方可以同时收发数据)。

  • 三次握手时,SYN 和 ACK 可以合并成一次(因为建立连接时双方都没有待发送的数据)

  • 四次挥手时,FIN 和 ACK 不能合并 ,因为被动关闭方收到 FIN 时,可能还有数据没发完,所以先回复 ACK 表示"收到了",等数据发完后再发 FIN

简单说:"收到你的关闭请求"和"我也要关闭"是两件事,中间可能隔了一段时间,所以不能合并。


四、四次挥手的关键状态

状态 所属方 含义
FIN_WAIT_1 主动方 已发 FIN,等待 ACK
CLOSE_WAIT 被动方 收到 FIN,等待自己发完剩余数据
FIN_WAIT_2 主动方 收到 ACK,等待被动方的 FIN
LAST_ACK 被动方 已发 FIN,等待最后的 ACK
TIME_WAIT 主动方 已发最后的 ACK,等待 2MSL 后真正关闭

五、面试高频追问

Q1:为什么要有 TIME_WAIT?为什么要等 2MSL?

两个原因:

  1. 确保最后一个 ACK 能被对方收到

    如果最后的 ACK 丢了,被动方会重发 FIN,主动方在 TIME_WAIT 期间可以重新回复 ACK。

  2. 让旧报文在网络中消失

    防止本次连接的"延迟报文"被下一次复用同一端口的连接误收。

MSL(Maximum Segment Lifetime)= 报文最大生存时间,2MSL 约等于 1~4 分钟(具体取决于操作系统)。


Q2:三次握手和四次挥手的对比

维度 三次握手(建立) 四次挥手(断开)
次数 3 次 4 次
核心原因 SYN 和 ACK 可合并 FIN 和 ACK 不能合并(可能有数据未发完)
状态数 较少 较多(多了 CLOSE_WAIT、TIME_WAIT 等)
能否携带数据 第三次可以(但不建议) 第二次之后可以继续发数据

Q3:如果主动方发出的 FIN 丢了怎么办?

主动方会超时重传 FIN,直到收到 ACK 或重传次数耗尽。


Q4:CLOSE_WAIT 状态过多会有什么问题?怎么解决?

  • 问题 :CLOSE_WAIT 表示被动方收到了 FIN 但没有调用 close() 关闭套接字。如果积压过多,会耗尽文件描述符,导致无法建立新连接。

  • 解决:检查服务端代码,确保收到 FIN 后及时调用 close(),或者设置 keepalive 探测。


Q5:如果已经建立了连接,但一方突然崩溃(没发 FIN)怎么办?

Keep-Alive 机制(心跳探测):

  • 定期发送探测报文

  • 如果多次无响应,则认为连接已死,主动释放


六、完整状态变迁图(简化版)

text

复制代码
[CLOSED] → (三次握手) → [ESTABLISHED] → (四次挥手) → [CLOSED]

主动方:                                     被动方:
ESTABLISHED                                 ESTABLISHED
    ↓ FIN                                         ↓
FIN_WAIT_1  → 收到ACK → FIN_WAIT_2      CLOSE_WAIT (等待应用关闭)
    ↓ 收到FIN                                   ↓ FIN
TIME_WAIT  ← 发ACK ← LAST_ACK
    ↓ 2MSL
  CLOSED                                     CLOSED

七、如果面试官再深挖,可能的追问方向:

  1. TCP 的保活机制(Keep-Alive)具体参数有哪些?(心跳间隔、重试次数)

  2. SYN Flood 攻击是什么?怎么防御?(半连接队列、SYN Cookie)

  3. 三次握手中,如果服务端的 SYN-ACK 丢了,两端分别会怎样?


相关推荐
Horn Still Sounds2 小时前
Linux网络编程|UDP与TCP传输层协议深度梳理
linux·网络·tcp/ip·udp
00后程序员张2 小时前
Android证书绑定抓包失败?Android SSL Pinning绕过实战指南
android·网络协议·计算机网络·网络安全·adb·https·ssl
比兔代理2 小时前
动态 IP 代理深度讲解:IP 地址轮换机制与会话保持方案
网络·网络协议·tcp/ip
蕾米莉亚《'';2 小时前
科普向host和port(感谢千问
网络
一直C2 小时前
Linux应用软件编程|TCP协议与Socket全套编程(三次握手、四次挥手、报文头部、核心机制)
linux·网络协议·tcp/ip·wireshark·vim·visual studio
玫幽倩2 小时前
2025MoeCTF(Pwn全)
网络·安全·pwn·ctf·新生赛·二进程·moectf
rcms152702692183 小时前
Novellus 27-033321-00 涡轮分子泵
网络
薛定e的猫咪3 小时前
(IEEE Transactions 2025)自适应元强化学习动态柔性作业车间调度框架
网络·人工智能·算法
tachibana23 小时前
如何设计多 Agent 的协作与动态切换机制?
网络·人工智能·ai·大模型·llm·agent