当前位置: 首页 > news >正文

TCP协议的三次握手与四次挥手深度解析

文章目录

一、前置知识:TCP 报文核心字段(理解握手 / 挥手的基础)

二、三次握手:建立可靠连接(含状态流转 + 报文细节)

1. 前提:连接初始化状态

2. 分步拆解(含状态变迁 + 报文实例)

3. 深度补充:三次握手的关键细节(

三、四次挥手:关闭可靠连接(含双向关闭 + 状态流转)

1. 前提:连接关闭初始化状态

2. 分步拆解(含状态变迁 + 报文实例)

3. 四次挥手的关键细节

四、总结:三次握手与四次挥手的核心对比(含异常场景)

五、实际运维 / 开发中的关联场景


一、前置知识:TCP 报文核心字段(理解握手 / 挥手的基础)

在拆解流程前,先明确 TCP 报文中与 “连接管理” 强相关的字段(这些字段是握手 / 挥手的 “沟通语言”):

字段

长度

核心作用

SYN

1 位

同步位,SYN=1表示 “发起连接同步请求”(仅在握手阶段使用,挥手阶段为 0)

ACK

1 位

确认位,ACK=1表示 “该报文包含确认号(ack)”(握手 / 挥手阶段均需置 1,除第一次 SYN)

FIN

1 位

终止位,FIN=1表示 “发起关闭连接请求”(仅在挥手阶段使用,握手阶段为 0)

seq

32 位

序号字段,标识 “当前报文的数据起始序号”(握手时传初始序号 ISN,数据传输时传数据序号)

ack

32 位

确认号字段,标识 “期望接收的下一个序号”(值 = 对方已发序号的最大值 + 1,即 “对方该序号及之前的报文已收到”)

Window

16 位

窗口大小,协商双方的 “接收缓冲区容量”(握手时确定初始窗口,传输时动态调整)

MSS

4 字节

最大分段大小,协商 “单次 TCP 报文能承载的最大数据量”(握手时确定,避免 IP 分片)

Checksum

16 位

校验和,检测报文是否在传输中损坏(确保握手 / 挥手报文不被篡改)

注意点:

  1. 只有ACK=1时,ack字段才有效;
  1. SYN=1或FIN=1的报文,即使没有数据,也会 “消耗 1 个序号”(后续数据序号需 + 1);
  1. 正常数据传输的报文,SYN=0且FIN=0,seq为数据起始序号。

二、三次握手:建立可靠连接

TCP 连接建立是 “客户端主动发起,服务器被动监听” 的过程,核心是双向确认收发能力 + 协商核心参数(ISN、MSS、窗口),以下结合 “状态变迁” 和 “实际报文例子” 拆解。

1. 前提:连接初始化状态
  • 客户端:初始状态为CLOSED(无连接),需先向服务器发起连接;
  • 服务器:提前进入LISTEN状态(通过bind()+listen()系统调用,监听指定端口,如 80、443)。
2. 分步拆解(含状态变迁 + 报文实例)

假设客户端生成的初始序号ISN_client=100,服务器生成的初始序号ISN_server=200,MSS 协商为 1460 字节(以太网环境默认),窗口大小协商为 8192 字节。

步骤

发起方

状态变迁

报文类型

完整报文字段(关键部分)

交互逻辑与细节

1

客户端

CLOSED → SYN_SENT

SYN 报文(第一次握手)

SYN=1,ACK=0(无需确认),seq=100(ISN_client),MSS=1460,Window=8192

① 客户端向服务器的目标端口(如 80)发送 “连接请求”,核心是传递自己的 ISN 和协商参数;② 为什么ACK=0?因为此时还未收到服务器任何报文,无确认内容;③ 客户端进入SYN_SENT状态:等待服务器的SYN+ACK响应,若超时(默认重传 3-5 次,间隔指数增长)则连接失败。

2

服务器

LISTEN → SYN_RCVD

SYN+ACK 报文(第二次握手)

SYN=1,ACK=1,seq=200(ISN_server),ack=100+1=101,MSS=1460,Window=8192

① 服务器收到 SYN 后,先校验(端口是否监听、MSS 是否支持),通过后返回 “同步 + 确认”;② ack=101的含义:“我已收到你序号 100 的 SYN 报文,下次请发 101 及以后的数据”;③ 服务器同时传递自己的 ISN(200),完成双向同步的第一步;④ 服务器进入SYN_RCVD状态:等待客户端的最终 ACK,若超时则释放资源。

3

客户端

SYN_SENT → ESTABLISHED

ACK 报文(第三次握手)

SYN=0,ACK=1,seq=100+1=101(SYN 消耗 1 个序号),ack=200+1=201,Window=8192

① 客户端收到SYN+ACK后,确认服务器的 ISN 和协商参数,返回最终确认;② seq=101的含义:“我的 SYN 报文(100)已消耗 1 个序号,后续数据从 101 开始”;③ ack=201的含义:“我已收到你序号 200 的 SYN 报文,下次请发 201 及以后的数据”;④ 客户端进入ESTABLISHED状态:连接正式建立,可开始传输数据;⑤ 服务器收到 ACK 后,也进入ESTABLISHED状态,双方开始双向数据传输。

3. 深度补充:三次握手的关键细节
  • ISN(初始序号)是怎么生成的?为什么不能固定为 1?

ISN 由操作系统动态生成,规则是 “基于系统时间戳(毫秒级)+ 随机偏移量”,确保每个新连接的 ISN 不同;

如果固定为 1,当 “旧连接的延迟报文”(如之前断开的连接中,未被及时丢弃的序号 1-10 的报文)到达新连接时,新连接会误认为是 “当前连接的合法数据”,导致数据错乱(比如覆盖正常数据)。

  • 什么是 “SYN 泛洪攻击”?如何防御?

攻击原理:攻击者伪造大量 “源 IP 不存在” 的 SYN 报文,向服务器发送,服务器收到后进入SYN_RCVD状态并等待 ACK,但永远收不到(源 IP 无效),最终服务器资源(端口、内存)被耗尽,无法处理正常连接;

防御方案:① 开启 TCP SYN Cookie(服务器不保存SYN_RCVD状态,用 ISN 和客户端 IP 生成 Cookie,后续 ACK 中验证);② 限制 SYN 报文的接收速率(如 iptables 规则);③ 缩短SYN_RCVD状态的超时时间(默认 30 秒,可改为 5 秒)。

  • 三次握手时,MSS 和 Window 字段的作用是什么?

① MSS(最大分段大小):协商 “单次 TCP 报文能携带的最大数据量”(MSS=MTU-IP 头 - TCP 头,以太网 MTU=1500,故 MSS=1500-20-20=1460),避免数据传输时触发 IP 分片(分片会降低效率);

② Window(窗口大小):协商 “双方接收缓冲区的最大容量”(如 8192 字节),后续数据传输时,发送方不能超过对方窗口大小发数据,避免接收方缓冲区溢出(这是 TCP 流量控制的基础)。

三、四次挥手:关闭可靠连接

        TCP 连接是 “全双工”(客户端→服务器、服务器→客户端两个方向独立传输),关闭时需 “分别关闭每个方向的连接”,因此需四次交互。以下结合 “状态变迁” 和 “文件传输场景” 拆解。

1. 前提:连接关闭初始化状态
  • 双方均处于ESTABLISHED状态,假设客户端已完成数据发送(如浏览器下载完网页),主动发起关闭;
  • 服务器可能仍有未发送完的数据(如服务器向客户端发送 “下载完成确认信息”)。
2. 分步拆解(含状态变迁 + 报文实例)

延续三次握手的序号:客户端当前序号seq=105(已发 101-105 共 5 字节数据),服务器当前序号seq=203(已发 201-203 共 3 字节数据)。

步骤

发起方

状态变迁

报文类型

完整报文字段(关键部分)

交互逻辑与细节

1

客户端

ESTABLISHED → FIN_WAIT_1

FIN 报文(第一次挥手)

FIN=1,ACK=1,seq=105(客户端最后发的序号),ack=203+1=204,Window=8192

① 客户端向服务器发送 “关闭请求”,核心是 “告知服务器:我这边的发送方向已无数据,准备关闭”;② seq=105的含义:“我已发完 101-105 的数据,FIN 报文占用 105 这个序号”;③ ack=204的含义:“我已收到你 201-203 的数据,下次请发 204 及以后的(若有)”;④ 客户端进入FIN_WAIT_1状态:等待服务器对 FIN 的 ACK 响应。

2

服务器

ESTABLISHED → CLOSE_WAIT

ACK 报文(第二次挥手)

FIN=0,ACK=1,seq=203(服务器最后发的序号),ack=105+1=106,Window=8192

① 服务器收到 FIN 后,先返回 ACK 确认 “已知道客户端要关闭发送方向”;② ack=106的含义:“我已收到你序号 105 的 FIN 报文,你这边的发送方向可以关闭了”;③ 服务器进入CLOSE_WAIT状态:此时服务器的 “接收方向已关闭”(不能再收客户端数据),但 “发送方向仍打开”(可继续向客户端发未完成的数据,如确认信息);④ 关键:CLOSE_WAIT状态的时长由服务器应用层决定 —— 若应用层没及时调用close(),服务器会一直停在这个状态(运维中 “CLOSE_WAIT 堆积” 就是这个原因)。

3

服务器

CLOSE_WAIT → LAST_ACK

FIN 报文(第三次挥手)

FIN=1,ACK=1,seq=203+1=204(服务器发完剩余数据后的序号),ack=106,Window=8192

① 服务器发完所有未完成的数据(如 “下载完成确认”)后,向客户端发送 “关闭请求”,告知 “我这边的发送方向也无数据了”;② seq=204的含义:“我已发完 201-203 的数据,现在发 FIN 报文,序号用 204”;③ 服务器进入LAST_ACK状态:等待客户端对 FIN 的 ACK 响应,若超时则重发 FIN(默认重传 3 次)。

4

客户端

FIN_WAIT_2 → TIME_WAIT → CLOSED

ACK 报文(第四次挥手)

FIN=0,ACK=1,seq=105+1=106(客户端 FIN 消耗 1 个序号),ack=204+1=205,Window=8192

① 客户端收到服务器的 FIN 后,返回 ACK 确认 “已知道服务器要关闭发送方向”;② ack=205的含义:“我已收到你序号 204 的 FIN 报文,你这边的发送方向可以关闭了”;③ 客户端不立即关闭,而是进入TIME_WAIT状态(等待 2MSL),再进入CLOSED;④ 服务器收到 ACK 后,立即进入CLOSED状态,释放所有资源。

3. 四次挥手的关键细节
  • 为什么服务器需要 “CLOSE_WAIT” 状态?什么情况下会出现 “CLOSE_WAIT 堆积”?

① CLOSE_WAIT是服务器 “处理剩余数据” 的缓冲状态 —— 服务器收到客户端 FIN 后,可能还有数据没发完(如数据库查询结果、文件收尾信息),需先传完数据再发自己的 FIN,因此需要CLOSE_WAIT过渡;

② “CLOSE_WAIT 堆积” 的原因:服务器应用层代码存在 bug,未调用close()函数释放连接(如处理完数据后忘记关闭 socket),导致服务器一直停在CLOSE_WAIT状态,端口和内存被耗尽(解决:检查应用层代码,确保数据发送完后调用close(),或设置 socket 超时自动关闭)。

  • TIME_WAIT 状态为什么要等 “2MSL”?MSL 的默认值是多少?

① MSL(Maximum Segment Lifetime):报文在网络中能存活的最长时间(默认 30 秒,不同操作系统可能调整),2MSL 即 60 秒;

② 等待 2MSL 的两个核心目的:

  • 防止最后一个 ACK 丢失:若服务器没收到客户端的 ACK,会在 1MSL 内重发 FIN,客户端在 2MSL 内还能收到并重发 ACK,避免服务器一直停在LAST_ACK;
  • 清空网络残留报文:2MSL 内,本次连接的所有报文(包括延迟的 FIN、ACK)会从网络中消失,新连接(用相同的源 IP、源端口、目的 IP、目的端口)不会收到旧报文干扰;

③ 特殊场景:若服务器需要快速重启(如运维更新),可通过net.ipv4.tcp_tw_reuse(复用 TIME_WAIT 状态的端口)或net.ipv4.tcp_tw_recycle(快速回收 TIME_WAIT 连接)优化,但需谨慎(可能导致报文错乱)。

  • “半关闭” 状态具体指什么?实际场景中如何体现?

半关闭是 “仅关闭一个方向的连接,另一个方向仍可传输数据” 的状态,对应步骤 1-2 后的状态:

例如:客户端(浏览器)向服务器下载 100MB 文件,下载完成后客户端发 FIN(步骤 1),服务器回 ACK(步骤 2):

  • 客户端的 “发送方向” 关闭(不能再向服务器发数据),但 “接收方向” 仍打开(能收服务器的 “下载完成确认”);
  • 服务器的 “接收方向” 关闭(不能再收客户端数据),但 “发送方向” 仍打开(可向客户端发 “确认信息”);

直到服务器发完确认信息并送 FIN(步骤 3),客户端确认后(步骤 4),才进入 “全关闭”。

总结:三次握手与四次挥手的核心对比

维度

三次握手(建立连接)

四次挥手(关闭连接)

核心目标

双向确认收发能力,协商 ISN、MSS、Window

双向关闭连接,确保双方数据均传输完成

状态流转

客户端:CLOSED→SYN_SENT→ESTABLISHED服务器:CLOSED→LISTEN→SYN_RCVD→ESTABLISHED

客户端:ESTABLISHED→FIN_WAIT_1→FIN_WAIT_2→TIME_WAIT→CLOSED服务器:ESTABLISHED→CLOSE_WAIT→LAST_ACK→CLOSED

关键报文

SYN → SYN+ACK → ACK

FIN → ACK → FIN → ACK

序号消耗

SYN 报文消耗 1 个序号,ACK 不消耗

FIN 报文消耗 1 个序号,ACK 不消耗

异常场景 1

SYN 丢失:客户端重传 SYN(指数退避)

FIN 丢失:服务器重传 FIN(默认 3 次)

异常场景 2

SYN 泛洪:服务器资源耗尽,无法处理正常连接

CLOSE_WAIT 堆积:服务器应用层未调用 close ()

实际举例

浏览器访问网站时,与服务器建立 TCP 连接

下载完成后,浏览器与服务器关闭 TCP 连接

五、实际运维 / 开发中的关联场景

  1. 查看 TCP 连接状态(Linux)

用netstat -an | grep :80或ss -tuln查看端口连接状态,若发现大量SYN_RCVD,可能是 SYN 泛洪;若大量CLOSE_WAIT,需检查应用层代码。

  1. TCP 连接超时配置

开发中需设置合理的 “连接超时”(如三次握手超时 3 秒)和 “读写超时”(如数据传输超时 30 秒),避免连接长期占用资源。

  1. HTTP 与 TCP 的关系

一次 HTTP 请求(如打开网页)对应 “一次 TCP 三次握手→传输 HTTP 数据→一次 TCP 四次挥手”(HTTP/1.1 默认长连接,会复用 TCP 连接,减少握手 / 挥手开销)。

        总的来说,用一句话简短的总结就是;TCP 三次握手通过 “SYN→SYN+ACK→ACK” 确认双方收发能力、协商初始参数以建立可靠连接,四次挥手通过 “FIN→ACK→FIN→ACK” 分方向确认数据传输完成以关闭全双工连接。好了,今天就到这里,今天依旧是深蹲不写BUG,希望这些东西对大家有所帮助。

http://www.xdnf.cn/news/1458289.html

相关文章:

  • 从头开始学习AI:第二篇 - 线性回归的数学原理与实现
  • 基础crud项目(前端部分+总结)
  • Flink反压问题
  • 算法 --- 分治(归并)
  • 【Markdown转Word完整教程】从原理到实现
  • VOC、COCO、YOLO、YOLO OBB格式的介绍
  • AgentThink:一种在自动驾驶视觉语言模型中用于工具增强链式思维推理的统一框架
  • 深入剖析Spring Boot / Spring 应用中可自定义的扩展点
  • elasticsearch学习(五)文档CRUD
  • 基于脚手架微服务的视频点播系统-界面布局部分(二):用户界面及系统管理界面布局
  • 02-ideal2025 Ultimate版安装教程
  • SPI flash挂载fatfs文件系统
  • 什么是静态住宅IP 跨境电商为什么要用静态住宅IP
  • More Effective C++ 条款28:智能指针
  • 稠密矩阵和稀疏矩阵的对比
  • 神马 M21 31T 矿机解析:性能、规格与市场应用
  • Python多序列同时迭代完全指南:从基础到高并发系统实战
  • vcruntime140_1.dll缺失?5个高效解决方法
  • 手机秒变全栈IDE:Claude Code UI的深度体验
  • SpringBoot实现国际化(多语言)配置
  • MySQL 8.0 主从复制原理分析与实战
  • 深入解析Java HashCode计算原理 少看大错特错的面试题
  • 多线程——线程状态
  • 并发编程——17 CPU缓存架构详解高性能内存队列Disruptor实战
  • ResNet(残差网络)-彻底改变深度神经网络的训练方式
  • linux——自定义协议
  • 多Agent协作案例:用AutoGen实现“写代码+测Bug”的自动开发流程
  • 秒店功能更新:多维度优化升级,助力商家经营
  • 当 LLM 遇上真实世界:MCP-Universe 如何撕开大模型 “工具能力” 的伪装?
  • 记录相机触发相关