TCP三次握手和四次挥手的过程详解

前言

TCP 是面向连接的可靠传输协议,连接建立依靠三次握手 ,连接断开依靠四次挥手。这两个机制是网络面试高频考点,也是后端、网络开发必须吃透的基础。

很多人只会死记流程,却不明白核心目的:为什么不能两次握手?为什么关闭连接需要四次而不是三次?本文结合报文标志位、交互流程、常见误区完整讲解。

前置知识:TCP 核心标志位

  • SYN:同步,用于建立连接,协商初始序列号
  • ACK:确认,确认收到对方报文
  • FIN:结束,代表一方不再发送新数据
  • seq:序列号,ack:确认应答号

一、TCP 三次握手(建立连接)

作用:客户端与服务端建立TCP连接。

目标:

  1. 双方确认自身发送、接收功能正常
  2. 协商彼此的初始序列号(ISN)
  3. 协商窗口大小、MSS等连接参数

角色定义:

  • Client:客户端(主动发起连接)
  • Server:服务端(监听端口,被动等待连接)

完整流程

  1. 第一次握手(Client → Server)

    客户端主动发送 SYN=1,携带客户端初始序列号 seq=x

    含义:客户端请求建立连接,我的起始序列号是x。

    客户端进入 SYN_SENT 状态。

  2. 第二次握手(Server → Client)

    服务端收到SYN报文,回复 SYN=1,ACK=1

  • seq=y:服务端自己的初始序列号
  • ack=x+1:确认收到客户端SYN,应答号 = 对方seq + 1
    服务端进入 SYN_RCVD 状态。
  1. 第三次握手(Client → Server)
    客户端收到服务端SYN+ACK报文,回复 ACK=1
  • ack=y+1:确认收到服务端的同步报文
  • seq = x+1
    客户端进入 ESTABLISHED(连接建立)
    服务端收到这条ACK后,也进入 ESTABLISHED,连接正式打通,可以传输业务数据。

简单形象理解:

客户端:"能听到我吗,我想建立连接"(第一次握手)

服务端:"收到,我也能联系你,我同意建立连接"(第二次握手)

客户端:"收到你的确认,我们开始通信"(第三次握手)

经典问题:为什么不能两次握手?

假设只有两次握手:

客户端发SYN → 服务端回复SYN+ACK,连接建立。

存在重大漏洞:历史延迟的SYN报文

客户端很早之前发送的连接请求,网络延迟很久才到达服务端。

服务端收到后直接建立连接,并分配资源。

但客户端早已放弃这条旧请求,不会收发数据。

服务端持续维持一条无效连接,白白占用内存、端口资源,造成服务器资源耗尽。

三次握手机制下,服务端必须等待客户端第三条ACK报文,才会正式建立连接。过期的SYN到达后,服务端回复SYN+ACK,但客户端不会响应,服务端超时后自动释放资源,避免资源浪费。

二、TCP四次挥手(断开连接)

TCP是全双工通信 ,双方可以独立收发数据。

任意一方想要关闭连接,只能关闭自己的发送通道,不能直接强制对方停止发送数据。因此断开连接需要四次交互。

完整流程

初始状态:双方都处于 ESTABLISHED

  1. 第一次挥手(Client → Server)

    客户端不再发送数据,发送 FIN=1,seq=u

    客户端进入 FIN_WAIT_1

    含义:客户端不再发送新数据,但仍然可以接收服务端还未发完的数据。

  2. 第二次挥手(Server → Client)

    服务端收到FIN,回复 ACK=1,ack=u+1

    服务端进入 CLOSE_WAIT

    客户端收到ACK,进入 FIN_WAIT_2

重点:此时单向通道关闭

客户端不能发数据,但是服务端如果还有剩余数据,依然可以继续发给客户端。

  1. 第三次挥手(Server → Client)

    当服务端所有数据全部发送完毕,没有数据要传输了,发送 FIN=1,seq=v

    服务端进入 LAST_ACK

    含义:服务端数据发送完成,我也要关闭连接。

  2. 第四次挥手(Client → Server)

    客户端收到FIN,回复 ACK=1,ack=v+1

    客户端进入 TIME_WAIT 状态;

    服务端收到这条ACK,立刻进入 CLOSED,连接关闭。

客户端需要等待 2MSL 时间之后,才最终切换到 CLOSED。

通俗理解:

客户端:我不再发消息给你了(第一次挥手)

服务端:收到,我知道你不发了,但是我还有消息先传给你(第二次挥手)

服务端:我的消息全部发完了,我也要结束对话(第三次挥手)

客户端:收到,结束通信(第四次挥手)

关键问题1:为什么挥手需要四次,握手只需要三次?

建立连接时,服务端的 SYN(同步)ACK(确认) 可以合并成一条报文,所以第二次握手合并两个动作。

关闭连接时:

服务端收到客户端FIN后,不能立刻发送FIN

需要先回复ACK,继续传输残留数据;等数据传输完毕,才能发送FIN。

ACK 和 FIN 无法合并,因此必须分成两条报文,总共四次交互。

关键问题2:客户端为什么要有 TIME_WAIT(2MSL)?

两个核心作用:

  1. 保证服务端能够正常收到最后的ACK报文

    如果客户端第四条ACK报文丢失,服务端处于LAST_ACK状态,会重传FIN报文。

    客户端处在TIME_WAIT期间,依然可以正常回复ACK。

    如果客户端直接关闭,端口立刻释放,收到重传FIN报文时只能返回RST,服务端无法正常关闭。

  2. 防止旧连接残留报文干扰新连接

    等待足够长的时间,确保网络中这条连接所有滞留数据包全部消失,避免旧报文被新建立的连接错误接收。

MSL:报文最大生存时间,Linux默认一般60s,2MSL就是两倍时长。

三、状态流转汇总(便于排查网络问题)

握手相关状态

  • LISTEN:服务端端口监听,等待连接
  • SYN_SENT:客户端发送SYN,等待服务端应答
  • SYN_RCVD:服务端收到SYN,等待客户端第三次ACK
  • ESTABLISHED:正常数据传输状态

挥手相关状态

  • FIN_WAIT_1:主动关闭方发送FIN,等待ACK
  • FIN_WAIT_2:收到ACK,等待对方发送FIN
  • CLOSE_WAIT:被动关闭方收到FIN,等待自身业务数据发送完毕
  • LAST_ACK:被动关闭方发送FIN,等待最后的ACK
  • TIME_WAIT:主动关闭方,等待2MSL
  • CLOSED:连接完全关闭

四、生产环境常见现象

  1. 服务器大量 CLOSE_WAIT

    典型原因:服务端代码收到对方关闭请求,程序没有调用socket关闭连接,没有发送FIN。代码层面socket资源泄漏。

  2. 大量 TIME_WAIT

    短连接高频创建销毁连接,大量主动关闭连接产生TIME_WAIT。

    解决方案:开启端口复用、调整tcp_tw_reuse内核参数。

  3. SYN_RECV 大量堆积

    可能遭遇SYN洪水攻击,或者服务端连接队列溢出。

五、总结

  1. 三次握手核心:协商序列号、验证双向收发能力,防御过期连接请求;SYN与ACK报文可以合并。
  2. 四次挥手核心:TCP全双工,两个方向通道独立关闭;ACK和FIN无法合并。
  3. TIME_WAIT 不是多余设计,是保障连接可靠关闭、隔离旧数据包的关键机制。
  4. 面试高频两大思考题:两次握手为什么不行?挥手为什么四次?掌握背后逻辑,不要死记硬背。

拓展建议:学习后可以使用 tcpdump / Wireshark 抓包,实际观察SYN、ACK、FIN报文,直观验证握手与挥手流程,理论结合抓包更容易理解。

相关推荐
奥莱维2 小时前
酒店客控系统与消防系统联动设计
网络
2401_868534783 小时前
《论单元测试及其应用》
网络·网络协议
小此方3 小时前
Linux网络(一):揭秘从网络发展哲学到 TCP/IP 协议栈分层设计的设计哲学
linux·网络·tcp/ip
星野爱8953 小时前
远程控制哪家安全性更高?ToDesk、UU远程、向日葵隐私屏深度测评!
linux·运维·网络
M哥支付3 小时前
什么是收付一体模式?
服务器·网络·其他·微信·金融
瓦学妹3 小时前
X(Twitter)新号如何防封?2026 养号与防限流全攻略
大数据·网络·人工智能·新媒体运营·twitter
Sagittarius_A*5 小时前
【RCELABS】Level 17~18 —— PHP命令执行函数与环境变量注入
开发语言·安全·web安全·靶场·php·rce
破碎的南瓜5 小时前
靶场中使用到的php函数以及每种漏洞的防御方式
开发语言·php
你怎么知道我是队长5 小时前
计算机虚拟存储管理与页面置换算法详解
服务器·网络·算法
谁看我谁 狼家二丫5 小时前
局域网文件共享实战:从“账户被禁用”到成功互传文件
开发语言·php