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 丢了,两端分别会怎样?


相关推荐
虎头金猫16 小时前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
wuyk55518 小时前
《WiFi 嵌入式物联网开发全套实战》| 第 16 章 ESP32 AP+STA 双模共存原理与工程坑点
网络·stm32·物联网
XUEYUAN521220 小时前
ASN 自治系统号风控:平台如何通过 IP 所属自治域批量识别代理流量
python·网络协议·http·网络安全·socks5
QYRdata21 小时前
年均增速24.2%!机器人数据湖未来六年增长动能强劲
网络·机器人·服务发现
CHENKONG_CK21 小时前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
chshang19921 天前
工业路由器是什么?浅谈5G工业网络中的IR602
网络·物联网·5g·智能路由器
萧瑟余晖1 天前
Netty 核心组件与 Reactor 模型详解
网络·架构
ITxiaobing20231 天前
IP 定位服务选型指南:从准确率到工程落地的技术考察
linux·服务器·网络
wuyk5551 天前
【Socket 进阶之路】第 9 章 Linux 网络服务量产稳定性优化|心跳保活、TIME_WAIT、SO_LINGER、内存池、断线重连、完整异常防护框架
linux·服务器·开发语言·网络·物联网
z落落1 天前
C#UDP+串口服务端+UDP 客户端(含 CRC16 校验)
网络·网络协议·udp