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

TCP 的状态可以分为「连接建立、数据传输、连接释放」三个阶段,下文按完整流程拆解每个状态的核心含义、触发场景与流转逻辑:

1. 连接建立阶段(三次握手)

这一阶段的核心目标是让客户端和服务器同步序列号,建立可靠的TCP通信连接。

状态 含义 典型场景
LISTEN 服务器监听指定端口,处于空闲等待状态,随时接收客户端的连接请求 服务器调用listen()系统函数后,进入该稳定监听状态
SYN_SENT 客户端已发送SYN握手包(第一次握手),等待服务器返回确认报文 客户端调用connect()发起连接请求后,立即进入该状态
SYN_RCVD 服务器成功接收客户端的SYN包,且已回复SYN+ACK报文(第二次握手),等待客户端最终ACK确认 服务器监听到客户端SYN连接请求并完成二次握手响应后,进入该状态
ESTABLISHED 三次握手流程全部完成,TCP连接正式建立,双方可正常收发数据 客户端收到SYN+ACK后回复ACK、服务器收到该ACK报文,双方同步进入该状态

补充:存在极少的「同时打开」特殊场景------客户端与服务器同时向对方发送SYN包,双方均会进入SYN_RCVD状态,互相回复SYN+ACK后,最终同步进入ESTABLISHED状态。


2. 数据传输阶段

本阶段仅有一个核心状态:ESTABLISHED

该状态下TCP连接处于活跃可用状态,通信双方无主次区分,可双向自由发送、接收数据,是TCP连接的核心工作状态。


3. 连接释放阶段(四次挥手)

(服务器发送的FIN包,默认携带ACK标志位,因此第三次挥手的报文自带确认属性)

TCP为全双工通信协议,双向数据通道需分别关闭,因此连接释放需要四次报文交互,即「四次挥手」。核心需区分主动关闭方被动关闭方的不同状态流转流程:

(1)被动关闭方(典型为服务器,图中右侧虚线框)

客户端主动发起连接关闭时,服务器的完整状态流转:

  1. ESTABLISHED → 收到客户端FIN包(第一次挥手)、回复ACK确认(第二次挥手) → 进入 CLOSE_WAIT 状态。
  • CLOSE_WAIT:服务器已感知客户端主动关闭单向通道,但自身可能仍有未传输完成的数据,需等待应用层调用close()主动关闭连接。
  1. 应用层执行close(),发送FIN关闭包(第三次挥手) → 进入 LAST_ACK 状态。

  2. 收到客户端的最终ACK确认包(第四次挥手) → 进入 CLOSED 状态,连接彻底释放。

(2)主动关闭方(典型为客户端,图中左侧虚线框)

客户端主动发起连接关闭的完整状态流转:

  1. ESTABLISHED → 应用层调用close(),发送FIN关闭包(第一次挥手) → 进入 FIN_WAIT_1 状态。

  2. 收到服务器的ACK确认包(第二次挥手) → 进入 FIN_WAIT_2 状态,持续等待服务器的FIN关闭包。

  3. 收到服务器的FIN关闭包(第三次挥手),回复ACK确认包(第四次挥手) → 进入 TIME_WAIT 状态。

  • TIME_WAIT:固定等待 2MSL(最长报文寿命的2倍),核心目的是确保服务器成功接收最终ACK包,同时拦截链路中残留的旧数据包,避免干扰新连接。
  1. 2MSL计时结束 → 进入 CLOSED 状态,连接彻底关闭。

close()CLOSING 补充:存在「同时关闭」特殊场景------通信双方同时调用发送FIN包,互相回复ACK后进入 状态,收到对方ACK后转入TIME_WAIT状态,最终完成连接关闭。


客户端 + 服务器 完整通信流程(典型HTTP请求场景)

结合流程主线,完整梳理一次标准HTTP请求的TCP状态全流转:

  1. 服务器:CLOSED → 执行socket()创建套接字→bind()绑定端口→listen()开启监听 → 进入 LISTEN 状态(监听业务端口)。

  2. 客户端:CLOSED → 执行socket()创建套接字→connect()发起连接→发送SYN包 → 进入 SYN_SENT 状态。

  3. 服务器接收客户端SYN包,回复SYN+ACK报文 → 进入 SYN_RCVD 状态。

  4. 客户端接收SYN+ACK报文,回复ACK确认 → 进入 ESTABLISHED 状态,开始发送HTTP请求数据。

  5. 服务器接收客户端ACK报文 → 同步进入 ESTABLISHED 状态,处理客户端请求并准备响应数据。

  6. 客户端接收服务端响应数据,调用close()关闭连接,发送FIN包 → 进入 FIN_WAIT_1 状态。

  7. 服务器接收FIN包,回复ACK确认 → 进入 CLOSE_WAIT 状态,处理剩余未完成数据。

  8. 客户端接收服务器ACK包 → 进入FIN_WAIT_2 状态,等待服务器FIN关闭包。

  9. 服务器处理完所有数据,调用close()发送FIN包 → 进入 LAST_ACK 状态。

  10. 客户端接收服务器FIN包,回复ACK确认 → 进入 TIME_WAIT 状态,启动2MSL计时。

  11. 服务器接收最终ACK包 → 进入 CLOSED 状态,服务端连接立即关闭。

  12. 客户端2MSL计时结束 → 进入 CLOSED 状态,本次TCP连接彻底销毁。


常见异常状态问题分析

  1. CLOSE_WAIT 数量过多 :说明被动关闭方(多为服务器)已收到对方FIN关闭请求,但应用层代码未及时调用close()释放连接,大概率是程序逻辑漏洞,会导致连接堆积、系统资源占用过高。

  2. TIME_WAIT 数量过多:主动关闭方(多为客户端)关闭连接后必然进入该状态并等待2MSL。若服务器作为主动关闭方,大量TIME_WAIT状态会持续占用端口资源,导致端口耗尽、服务性能下降,可通过调整Linux内核参数优化缓解。


TIME_WAIT 状态深度解析

客户端在收到服务器的结束报文段后,不会直接进入CLOSED状态,而是转入TIME_WAIT状态,固定等待2MSL(报文段最大生存时间)时长后,才会彻底关闭连接。

TIME_WAIT 状态存在的核心意义有两点:

  • 可靠终止整条TCP连接,避免连接残留异常;

  • 确保链路中延迟滞留的旧TCP报文段被完全识别、丢弃,避免干扰新连接。

第一点可靠终止连接:若客户端回复的最终ACK报文丢失,服务器会超时重发FIN结束报文。客户端停留在TIME_WAIT状态,可及时接收重发的FIN包并重新发送ACK确认。若无该状态,客户端会直接释放连接,以复位报文回应服务器,服务器会判定连接异常报错,无法正常关闭连接。

第二点规避旧报文干扰:Linux系统中,同一TCP端口无法被重复复用。若没有TIME_WAIT状态,新程序可立即复用刚关闭连接的相同IP+端口,创建「连接化身」。此时链路中滞留的旧连接延迟报文,会被新连接接收,导致数据错乱、通信异常。TIME_WAIT的2MSL等待时长,可确保所有旧连接报文彻底失效、被网络丢弃。

TIME_WAIT状态会占用端口资源,导致程序无法立即重启:服务进程退出后,残留的TIME_WAIT连接会占用对应端口,新进程无法绑定端口启动,需等待2MSL超时释放。

客户端通常使用系统随机分配的临时端口建立连接,重启后大概率不会复用旧端口,因此客户端程序一般可立即重启,不受TIME_WAIT影响。

而服务器固定使用知名端口对外提供服务,若服务器主动关闭连接、残留TIME_WAIT状态,会导致端口被占用,无法立即重启服务。可通过配置Socket选项 SO_REUSEADDR,强制进程复用处于TIME_WAIT状态的端口,实现服务快速重启。

四次挥手中,主动发送FIN包发起关闭、且最后回复ACK确认对方FIN的一方,才会进入TIME_WAIT状态、等待2MSL时长。

核心总结:

  • 率先调用 close() 发送FIN包的一方,为主动关闭方;

  • 主动关闭方接收对方FIN包、回复ACK后,必然进入TIME_WAIT状态;

  • 被动关闭方仅在收到FIN后响应ACK,最终接收对方ACK后直接进入CLOSED状态,不会产生TIME_WAIT

(原笔记:GameServer-Learning/00-Notes/Network/linux-high-performance at main · maomianbaobumoyu/GameServer-Learning)

相关推荐
羑悻的小杀马特1 小时前
【动态规划篇】正则表达式与通配符:开启代码匹配的赛博奇幻之旅
c++·算法·leetcode·正则表达式
ch.ju1 小时前
Java程序设计(第3版)第四章——引用
java·开发语言
Huangjin007_2 小时前
【C++ STL篇(十三)】无序关联容器 unordered_set / unordered_map解析
开发语言·c++
爱吃苹果的梨叔2 小时前
2026年KVM over IP分布式方案选型指南:清虹创智远程集中管控与坐席协作
分布式·网络协议·tcp/ip
白日与明月2 小时前
pip下载库指定操作系统及python版本
开发语言·python·pip
折哥的程序人生 · 物流技术专研2 小时前
Qoder 1.0 完全指南:从安装到Agents驱动开发实战
开发语言·人工智能·python·ai编程
Amnesia0_02 小时前
传输层协议UDP和TCP
linux·网络·tcp/ip·udp
minji...2 小时前
Linux 高级IO(三)多路转接之poll,poll的原理,poll版本的TCP服务器的实现
linux·服务器·网络·select·多路转接·epoll·poll
Xin_ye100862 小时前
C# 零基础到精通教程 - 第十六章:ASP.NET Core Web API——构建现代 Web 服务
开发语言·c#