TCP(传输控制协议)是互联网最重要的协议之一,它保证了数据的可靠、有序传输。连接建立时的“三次握手”和连接关闭时的“四次挥手”是其核心机制,涉及特定的报文交换和状态变化。

一、TCP 三次握手(Three-Way Handshake) - 建立连接

目的:同步双方的初始序列号(Sequence Number,简称 Seq),确认对方能够正常收发数据,建立双向连接。

状态变化详细过程:

  1. CLOSED -> LISTEN(服务器端):
    • 服务器启动,调用 listen() 进入 LISTEN 状态,准备接受连接请求。
  2. SYN_SENT(客户端):
    • 客户端调用 connect() 主动发起连接请求。
    • 客户端发送一个 SYN 报文:
      • SYN 标志位设置为 1
      • 随机生成一个初始序列号 client_seq = x
      • 无确认号(因为还没收到对方的任何序列号)。
    • 客户端进入 SYN_SENT 状态(表示已发送 SYN,等待对方的 SYN+ACK)。
  3. LISTEN -> SYN_RCVD(服务器端):
    • 服务器处于 LISTEN 状态,接收到客户端发来的 SYN 报文。
    • 服务器决定接受连接,并发送一个 SYN + ACK 报文:
      • SYN 标志位设置为 1
      • ACK 标志位设置为 1
      • 随机生成一个初始序列号 server_seq = y
      • 将确认号 ack = x + 1(因为客户端的 SYN 占用了序列号 x,所以服务器期望收到客户端发来的下一个数据字节的序列号是 x+1)。
    • 服务器进入 SYN_RCVD 状态(表示已发送 SYN+ACK,等待客户的 ACK)。
  4. SYN_SENT -> ESTABLISHED(客户端):
    • 客户端处于 SYN_SENT 状态,收到服务器发来的 SYN + ACK 报文。
    • 客户端发送一个 ACK 报文:
      • ACK 标志位设置为 1
      • 序列号 seq = x + 1(因为客户端的 SYN 报文占用了序列号 x,所以下一个报文的序列号是 x+1)。
      • 确认号 ack = y + 1(因为服务器的 SYN 报文占用了序列号 y,所以客户端期望收到服务器发来的下一个数据字节的序列号是 y+1)。
    • 客户端进入 ESTABLISHED 状态(表示连接已建立)。
  5. SYN_RCVD -> ESTABLISHED(服务器端):
    • 服务器处于 SYN_RCVD 状态,收到客户端发来的 ACK 报文。
    • 服务器验证该 ACK 报文的确认号 ack 是否等于 y + 1
    • 验证通过后,服务器也进入 ESTABLISHED 状态(表示连接已建立)。

至此,双向通信通道建立完成。

二、TCP 四次挥手(Four-Way Handshake) - 关闭连接

目的:双方都确认对方不再发送数据,安全地终止双向连接。

状态变化详细过程:

  1. ESTABLISHED -> FIN_WAIT_1(主动关闭方 - 通常是客户端):
    • 主动关闭方(A)调用 close() 或进程退出。
    • A 发送一个 FIN 报文:
      • FIN 标志位设置为 1
      • 序列号 seq = u(等于 A 要发送的下一个数据的序列号,但 FIN 消耗一个序列号)。
    • A 进入 FIN_WAIT_1 状态(表示已发送 FIN,等待对方的 ACK 对方的 FIN)。
  2. ESTABLISHED -> CLOSE_WAIT(被动关闭方):
    • 被动关闭方(B)处于 ESTABLISHED 状态,收到 A 发来的 FIN 报文。
    • B 知道自己该方向的数据发送通道将被关闭(应用程序会收到 EOF)。
    • B 发送一个 ACK 报文:
      • ACK 标志位设置为 1
      • 序列号 seq = v(B 自己的下一个序列号)。
      • 确认号 ack = u + 1(表示收到了 A 的 FIN 报文)。
    • B 进入 CLOSE_WAIT 状态(表示收到对方的 FIN,自己的关闭过程开始,等待自己的应用程序通知关闭)。此时:A 到 B 的发送通道已关闭(A不再发送数据),但 B 到 A 的发送通道可能还有数据需要发送。
  3. FIN_WAIT_1 -> FIN_WAIT_2(主动关闭方):
    • A 处于 FIN_WAIT_1 状态,收到 B 发来的 ACK 报文。
    • A 验证该 ACK 报文的确认号 ack 是否等于 u + 1
    • 验证通过后,A 进入 FIN_WAIT_2 状态(表示已收到对方对 FIN 的 ACK,等待对方发送 FIN)。
  4. CLOSE_WAIT -> LAST_ACK(被动关闭方):
    • B 处于 CLOSE_WAIT 状态,完成了自己方向的数据发送(应用程序调用 close())。
    • B 发送一个 FIN 报文:
      • FIN 标志位设置为 1
      • 序列号 seq = w(这个序列号可能等于 v(如果 CLOSE_WAIT 期间 B 没有发数据)或大于 v(如果 B 发过数据))。
      • 确认号 ack 仍然是 u + 1(因为在这个方向上 A 没有新数据)。
    • B 进入 LAST_ACK 状态(表示自己已发送 FIN,等待对方最后的 ACK)。
  5. FIN_WAIT_2 -> TIME_WAIT(主动关闭方):
    • A 处于 FIN_WAIT_2 状态,收到 B 发来的 FIN 报文。
    • A 发送一个 ACK 报文:
      • ACK 标志位设置为 1
      • 序列号 seq = u + 1(之前的 FIN 报文序列号是 u)。
      • 确认号 ack = w + 1(确认 B 的 FIN 报文)。
    • A 进入 TIME_WAIT 状态(也称为 2MSL Wait 状态)。此状态会持续一段时间(通常为 2 * Maximum Segment Lifetime (MSL),默认在 Linux 中是 60 秒)。
  6. LAST_ACK -> CLOSED(被动关闭方):
    • B 处于 LAST_ACK 状态,收到 A 发来的 ACK 报文。
    • B 验证该 ACK 报文的确认号 ack 是否等于 w + 1
    • 验证通过后,B 关闭连接,进入 CLOSED 状态。
  7. TIME_WAIT -> CLOSED(主动关闭方):
    • A 在 TIME_WAIT 状态等待 2MSL 时间。
    • 目的:
      • 确保最后一个 ACK 报文送达 B: 如果 B 没有收到最后一个 ACK(它在 LAST_ACK 状态等待),会在超时后重发 FIN。处于 TIME_WAIT 的 A 收到这个重发的 FIN,会再次发送 ACK。
      • 确保网络中所有旧的报文段消散: 防止具有相同四元组(源IP、源端口、目的IP、目的端口)的下一个新连接,错误地接收和处理上一个旧连接的残留报文。
    • 2MSL 时间到,A 关闭连接,进入 CLOSED 状态。

至此,连接完全终止。

核心问题解答

为什么需要“三次”握手?两次握手不行吗?

不行。 原因主要有:

  1. 避免失效连接请求造成的资源浪费和历史连接问题:
    • 场景: 假设客户端发送了第一个 SYN=1 请求(X),但因网络拥塞严重延迟。客户端超时未收到响应,会重发第二个 SYN=1 请求(Y)。Y 成功到达,服务器响应 SYN+ACK,客户端也响应 ACK,完成三次握手建立连接。通信结束,连接关闭。
    • 问题: 现在那个延迟了的初始 SYN 请求 X 终于到达了服务器。如果只有两次握手(服务器收到 SYN -> 响应 SYN+ACK -> 建立连接),服务器会误以为这是一个新的连接请求(历史连接),并立即为其分配资源(建立连接表项、分配缓冲区等)。
    • 后果: 服务器资源被无意义占用(因为客户端此时根本不知道还有这个连接存在,也不会发送数据)。此外,如果这个“幽灵连接”被分配了新的序列号,也可能干扰后续真正的新连接(相同端口复用)。
    • **解决:**三次握手中的第三次握手(ACK)就是客户端的明确确认信号。 当那个延迟的 SYN 包 X 到达服务器时,服务器会发送 SYN+ACK,但客户端已经关闭了最初的连接意图,它会忽略这个 SYN+ACK 或者发送 RST 拒绝。这样服务器就不会为这个无效请求建立连接。
  2. 初始序列号同步的双向确认:
    • 通信双方都需要知道对方的初始序列号。两次握手只能确保客户端知道服务器的初始序列号(在服务器的 SYN+ACK 中),并确认服务器的发送能力。但服务器在第二次握手时发送的 SYN+ACK,并未得到客户端的确认(仅两次握手的话,服务器在第二步就认为连接建立了)。
    • 问题: 服务器不知道客户端是否成功收到了自己的序列号 y。如果这个 SYN+ACK 丢失了,服务器认为自己建立了连接(已发送SYN+ACK -> 等待ACK),但客户端还在等待 SYN+ACK(它没收到),双方状态不一致。
    • **解决:**第三次握手的 **ACK** 报文明确告诉服务器:“我收到了你的初始序列号 **y**,我期望的下一个序列号是 **y+1**”。 这完成了服务器序列号的同步确认。

总结: 三次握手是保证可靠性、防止建立错误连接、且完成序列号双向同步确认的最小开销方案。

为什么需要“四次”挥手?

主要原因是:TCP 连接是全双工(Full-Duplex)的。

  1. 双向独立的关闭通道:
    • 当客户端发送 FIN 时,表示它数据发送完毕(不再往服务器写数据),但服务器到客户端方向的数据发送通道并未立即关闭。
    • 服务器收到 FIN 后,知道自己该方向的数据接收通道已关闭(收到EOF),但需要检查自己的应用程序是否还有数据要发送给客户端。如果还有数据要发送(比如最后要确认客户端请求操作成功的消息),服务器会在 CLOSE_WAIT 状态继续发送这些数据。
    • 只有等待服务器自己也确定所有数据都发送完毕(应用层调用 close())时,它才会发送自己的 FIN 来关闭“服务器->客户端”方向的发送通道。
    • 因此,关闭连接需要四个步骤:
      • A -> B 发送 FIN:关闭 A 的发送通道。
      • B -> A 发送 ACK:确认收到 A 的 FIN。此时 B 的接收通道关闭(知道 A 不再发数据)。
      • B -> A 发送 FIN:关闭 B 的发送通道。(这条 FIN 的发送时间独立于前面的 ACK)
      • A -> B 发送 ACK:确认收到 B 的 FIN。
  2. FIN 和 ACK 可能无法合并:
    • 当 B 收到 A 的 FIN 时,它必须立即响应一个 ACK(这是协议要求)。但此时 B 的应用程序可能还未决定关闭/发送完自己的数据(处于 CLOSE_WAIT 状态),因此 B 的 FIN 报文无法像第二次握手(SYN+ACK)那样与此时的 ACK 合并发送。ACK 必须在收到 FIN 后立即发送,而 FIN 必须等 B 准备好关闭其发送端时才发送。

总结: 四次挥手是 TCP 全双工特性决定的。发送 FIN 意味着“我这边不准备再发送数据了”。两次挥手只能关闭一个方向(A->B),四次挥手才能彻底关闭两个独立的数据发送通道(A->B 和 B->A),确保数据完整性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919197.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919197.shtml
英文地址,请注明出处:http://en.pswp.cn/news/919197.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Applications Manager进行 Apache Solr 监控

Apache Solr 为一些对性能极为敏感的环境提供搜索支持:电子商务、企业应用、内容门户和内部知识系统。因此,当出现延迟增加或结果不一致的情况时,用户会立刻察觉。而当这些问题未被发现时,情况会迅速恶化。 Apache Solr 基于 Apa…

Shell脚本-for循环语法结构

一、前言在 Linux Shell 脚本编程中,for 循环 是最常用的控制结构之一,用于重复执行一段命令,特别适用于处理列表、文件、数字序列等场景。本文将详细介绍 Shell 脚本中 for 循环的各种语法结构,包括:✅ 经典 for in 结…

记SpringBoot3.x + Thymeleaf 项目实现(MVC架构模式)

目录 前言 一、创建SpringBoot项目 1. 创建项目 2. 运行项目 二、连接数据库实现登录 1. pom.xml文件引入依赖包 2. application.yml文件配置 3. 数据持久层,mybatis操作映射 4. Service接口及实现 5. Controller代码 6. Thymeleaf页面登录 7. 运行项目…

Java 导出word 实现表格内插入图表(柱状图、折线图、饼状图)--可编辑数据

表格内插入图表导出效果表格内图表生成流程分析 核心问题与解决方案 问题 Word 图表作为独立对象,容易与文本分离位置难以精确控制,编辑时容易偏移缺乏与表格数据的关联性 解决方案 直接嵌入:将图表嵌入表格单元格,确保数据关联精…

北京JAVA基础面试30天打卡12

1.MySQL中count(*)、count(I)和count(字段名)有什么区别? 1**.COUNT ()**是效率最高的统计方式:COUNT()被优化为常量,直接统计表的所有记录数,不依赖字段内容,开销最低。推荐在统计整个表的记录数时使用。 2.**COUNT(1…

【AI】——结合Ollama、Open WebUI和Docker本地部署可视化AI大语言模型

🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大三学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL&#xff0…

RAG学习(二)

构建索引 一、向量嵌入 向量嵌入(Embedding)是一种将真实世界中复杂、高维的数据对象(如文本、图像、音频、视频等)转换为数学上易于处理的、低维、稠密的连续数值向量的技术。 想象一下,我们将每一个词、每一段话、…

亚马逊店铺绩效巡检_影刀RPA源码解读

一、项目简介 本项目是一个基于RPA开发的店铺绩效巡店机器人。该机器人能够自动化地登录卖家后台,遍历多个店铺和站点,收集并分析各类绩效数据,包括政策合规性、客户服务绩效、配送绩效等关键指标,并将数据整理到Excel报告中&…

跨越南北的养老对话:为培养“银发中国”人才注入新动能

2025年8月16日,北京养老行业协会常务副会长陈楫宝一行到访广州市白云区粤荣职业培训学校,受到颐年集团副总李娜的热情接待。此次访问不仅是京穗两地养老行业的一次深度交流,更为推动全国智慧养老体系建设、提升养老服务专业化水平注入了新动能…

Spring IOC 学习笔记

1. 概述Spring IOC(Inversion of Control,控制反转)是一种设计思想,通过依赖注入(Dependency Injection,DI)实现。它的核心思想是将对象的创建和依赖关系的管理交给Spring容器,从而降…

揭开Android Vulkan渲染封印:帧率暴增的底层指令

ps:本文内容较干,建议收藏后反复边跟进源码边思考设计思想。壹渲染管线的基础架构为什么叫渲染管线?这里是因为整个渲染的过程涉及多道工序,像管道里的流水线一样,一道一道的处理数据的过程,所以使用渲染管…

HTTP 请求转发与重定向详解及其应用(含 Java 示例)

在 Web 开发中,我们经常需要在不同页面之间跳转,比如登录成功后跳到首页、提交表单后跳到结果页面。这时,常见的两种跳转方式就是 请求转发(Request Forward) 和 重定向(Redirect)。虽然它们都能…

如何将 MCP Server (FastMCP) 配置为公网访问(监听 0.0.0.0)

如何将 MCP Server (FastMCP) 配置为公网访问(监听 0.0.0.0)引言常见错误尝试根本原因:从源码解析正确的解决方案总结引言 在使用 Model Context Protocol(MCP) 框架开发自定义工具服务器时,我们经常使用 …

The Network Link Layer: 无线传感器中Delay Tolerant Networks – DTNs 延迟容忍网络

Delay Tolerant Networks – DTNs 延迟容忍网络架构归属Delay Tolerant Networks – DTNs 延迟容忍网络应用实例例子 1:瑞典北部的萨米人 (Saami reindeer herders)例子 2:太平洋中的动物传感网络DTNs路由方式——存储&转发DTNs移动模型Random walk …

计算机视觉(opencv)实战二——图像边界扩展cv2.copyMakeBorder()

OpenCV copyMakeBorder() 图像边界扩展详解与实战在图像处理和计算机视觉中,有时需要在原始图像的四周增加边界(Padding)。这种操作在很多场景中都有应用,比如:卷积神经网络(CNN)中的图像预处理…

ansible管理变量和事实

ansible管理变量和事实与实施任务控制 在 Ansible 中,变量和事实(Facts)就像给剧本(Playbook)配备的 “信息工具箱”,让你的自动化配置管理更灵活、更智能。 变量:提前准备的 “预设信息” 变…

STM32--寄存器与标准库函数--基本定时器

目录 前言 基本定时器概念 定时时间 定时器时钟确定 倍频锁相环被正确配置为168MHz 定时器的库函数操作 代码 定时器的寄存器操作 代码 寄存器 后言 前言 使用平台:STM32F407ZET6 使用数据手册:STM32F407数据手册.pdf 使用参考手册&…

PCA 实现多向量压缩:首个主成分的深层意义

PCA 实现多向量压缩 第一个主成分(components_[0])正是数据协方差矩阵中最大特征值对应的特征向量。 ,layer_attention_vector[layer] 被赋值为 pca.components_[0],这确实是一个特征向量,具体来说是 PCA 分解得到的第一个主成分(主特征向量)。 关于它的维度: 假设 c…

网络常识-DNS如何解析

DNS(Domain Name System,域名系统)是互联网的“地址簿”,负责将人类易记的域名(如www.example.com)转换为计算机可识别的IP地址(如192.168.1.1)。其工作流程可以简单理解为“从域名到…

Java中 23 种设计模式介绍,附带示例

文章目录设计模式六大原则设计模式分类1、创建型模式(Creational Patterns)2、结构型模式(Structural Patterns)3、行为型模式(Behavioral Patterns)一、创建型模式(Creational Patterns&#x…