【Java 网络编程】TCP 连接 断开 机制 ( 三次握手 | 四次挥手 )

本文涉及的产品
数据传输服务 DTS,同步至DuckDB 3个月
简介: 【Java 网络编程】TCP 连接 断开 机制 ( 三次握手 | 四次挥手 )

文章目录

I TCP 连接建立流程 ( 三次握手 )

II SYN 和 ACK 中的随机值

III TCP 连接建关闭流程 ( 四次挥手 )

IV TCP 连接断开的保证

V 四次挥手的必要性



I TCP 连接建立流程 ( 三次握手 )


1. 连接两端点 : 客户端 , 发起连接 ; 服务器端 , 等待客户端的连接 ;


2. 初始状态 : 客户端发起连接 , 服务器端处于被动等待连接状态 ;


3. 客户端发送 SYN 命令 : 客户端发起连接时 , 向服务器端发送 SYN 命令 ;


① 发送命令 : 客户端向服务器端发送 SYN 命令 ( 连接请求命令 ) ;

② SYN 参数 : 该命令会携带一个随机值参数 x , 该命令发送给服务器 ;

4. 服务器端收到 SYN 命令并处理 ( 第一次握手 ) : 服务器端收到 SYN 命令 , 向客户端会送 SYN ACK 命令 ;


① 校验命令 : 服务器端收到客户端发送的 SYN 命令 , 会校验该命令的正确性 ;

② 命令回送 : 如果 SYN 命令校验通过 , 服务器端会送一条 SYN ACK 命令 ;

③ 命令组成 : 该 SYN ACK 指令包含两个指令 , 即 接收到的 SYN 指令 , 和服务器端生成的 ACK 指令 ;

④ SYN 指令处理 : 服务器端收到客户端发送的 SYN 指令 , 该指令有一个随机值 x , 服务器端会送时 , 会将该 x 执行 +1 操作 ; 即会送的参数是 x + 1 ;

⑤ ACK 指令参数 : ACK 指令会自带一个随机值参数 y ;

5. 客户端接收并处理 SYN ACK 命令 ( 第二次握手 ) : 客户端收到服务器端会送的 SYN ACK 命令后 , 会先进行校验 , 将 ACK 中的 y 参数执行自增操作 , 再次将 SYN ( x + 1 ) ACK ( y + 1 ) 命令发送给服务器端 ;


6. 服务器端收到 SYN ACK 命令 ( 第三次握手 ) : 服务器端再次收到客户端的命令 , 校验这两个命令 , 校验通过后 , 连接正式建立 ;


image.png




II SYN 和 ACK 中的随机值


1. 服务器对应多个客户端 : 服务器是需要接收很多客户端的连接 , 那就需要针对不同的客户端进行区分操作 , 这里从客户端发送的随机数有效的将该客户端与其它客户端进行了区别 ;


2. 连接举例 : 客户端 A 向服务器 S 发送 SYN 命令携带了随机参数 X , 客户端 B 向服务器 S 发送 SYN 命令携带参数 Y , X 和 Y 一定不能相同 ;


① 客户端 A 发送 SYN 携带随机数 X , 服务器 S 向客户端 A 回送 X + 1 ;

② 客户端 B 发送 SYN 携带随机数 Y , 服务器 S 向客户端 B 回送 Y + 1 ;

③ 如果服务器 S 回送的指令相同 , 那么连接的可靠性便不能保证了 ;



III TCP 连接建关闭流程 ( 四次挥手 )


1. 客户端和服务器端都可以发起连接关闭的操作 , 这里拿客户端发起关闭连接操作举例 ;


2. 第一次挥手 ( 客户端 -> 服务器端 ) : 客户端当前状态是已连接状态 ( ESTABLISHED ) , 发送 FIN 命令 , 其会携带随机参数 seq = u 的值 ;


SYN 是发起连接的命令 , FIN 是断开连接的命令 ;


3. 第二次挥手 ( 服务器端 -> 客户端 ) : 服务器端当前状态也是已连接状态 ( ESTABLISHED ) , 接收到 FIN 命令后 , 会向客户端会送一条 ACK 命令 , 该 ACK 命令携带参数 ack = u+1 ;


4. 此时的服务器端状态 : 客户端发送请求断开命令后 , 服务器端并不能马上响应断开 , 如果数据还没有传输完 , 服务器端是不能断开的 , 只能等到服务器端剩余数据传输完毕之后 , 服务器端才能第三次挥手 ;


5. 此时的客户端状态 : 客户端接收到服务器端会送的 ACK 命令 ( ack = u + 1 ) , 此时客户端的输出连接就可以断开了 , 客户端不能进行输出操作 , 此时无法向服务器端发送数据了 , 但是客户端的输入功能没有关闭 , 客户端还可以接收服务器端的数据 ;


6. 服务器端操作 : 服务器端有可能还有残留数据没有完全送达客户端 , 此时将剩余数据传输给客户端 , 客户端目前是有接收功能的 ( 没有发送功能 ) , 直到送达之后才会执行下一步操作 ;


TCP 是可靠传输 , 必须保证数据全部正确可靠 , 这个步骤是必须的 ;


7. 第三次挥手 ( 服务器端 -> 客户端 ) : 服务器端将所有数据送出完毕后 , 向客户端发送 FIN 命令 , 表示服务器端想要关闭连接了 ;


8. 第四次挥手 ( 客户端 -> 服务器端 ) : 客户端收到服务器端的 FIN 命令后 , 再次向服务器端会送 ACK 命令 , 表示服务器端可以断开连接了 ;


image.png


第一次第二次挥手是客户端向服务器端申请断开连接 , 客户端发送断开请求命令 , 服务器端会送响应命令 ;

第三次第四次挥手是服务器端向客户端申请断开连接 , 服务器端发送断开请求命令 , 客户端会送响应命令 ;




IV TCP 连接断开的保证


1. 服务器端保证第三次挥手能到达客户端的机制 : 当服务器端向客户端发送 FIN 命令后 ( 第三次挥手 ) , 服务器端会进入等待状态 , 在等待状态中 , 服务器端会以一个间隔周期持续发送 FIN 命令 , 这个间隔是一帧数据发送所需的最长时间 ( SML 默认 30 秒) , 如果超过 30 秒服务器端没有收到客户端会送的 ACK 命令 ( 第四次挥手 ) , 服务器端会再次发送 FIN 命令 ( 多次第三次挥手 ) , 直到收到客户端会送的 ACK 命令 ( 第四次挥手 ) ;


2. 客户端保证第四次挥手能到达服务器端机制 : 如果客户端一直不向服务器端回送 ACK 命令 ( 第四次挥手 ) , 或者 ACK 命令未到达服务器端 , 服务器端会一直向客户端发送 FIN 命令 ( 第三次挥手 ) , 客户端不断的收到 FIN 命令 , 不停地向服务器端发送 ACK 命令 , 直到服务器端收到 ACK 命令 , 停止向客户端发送 FIN 命令 ;




V 四次挥手的必要性


1. 全双工断开 : 四次挥手保证了全双工连接的安全断开 , 全双工指的是客户端既可以接收服务器端的信息 , 也可以像服务器端发送消息 , 半双工只能发送或者接收消息 , 不能同时发送和接收消息 ;


2. 前两次挥手 : 这里的前两次挥手是断开客户端向服务器端发送数据的连接 , 客户端主动发起断开 , 因此其不会再向服务器端写出数据了 , 但是服务器端可能正在传输数据 , 因此这里还需要单独处理客户端接收数据的连接断开的操作 ;


3. 传输剩余数据 : 前两次挥手之后 , 客户端就丧失了向服务器端发送消息的能力 , 但是服务器端还可以向客户端发送消息 ; 利用这个空档 , 客户端需要将剩余的残余数据发送给客户端 , 然后主动发起断开与客户端的发送连接 ;


4. 后两次挥手 : 后两次挥手就是断开服务器端向客户端传输数据的连接 , 因此是服务器端发送断开请求指令 ;


5. 不能是三次挥手 : 第二次和第三次挥手不能合并 , 因为第二次挥手后 , 无法保证服务器端可以马上关闭连接 , 如果服务器端正在向客户端发送数据 , 要确保最后一批数据能完整的送达客户端 , 因此第二次挥手仅能代表客户端向服务器端的连接关闭 , 不能强行关闭服务器端向客户端传输数据的通道 , 需要等待数据传输完毕后 , 才能发起第三次挥手 , 第二次挥手和第三次挥手中间有一定的时间间隔 , 服务器端要利用这个间隔将剩余数据传输完毕 ;


6. 不能是五次挥手 : 目前需要断开两个连接 , 分别是发送和接收两个双工连接 , 每个连接段考只需要发送请求 FIN 指令 和 会送 ACK 指令即可完成 , 四次就可以完成两个连接的断开操作 , 多余的指令没有必要 ;


相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
设计模式 人工智能 安全
AQS:Java 中悲观锁的底层实现机制
AQS(AbstractQueuedSynchronizer)是Java并发包中实现同步组件的基础工具,支持锁(如ReentrantLock、ReadWriteLock)和线程同步工具类(如CountDownLatch、Semaphore)等。Doug Lea设计AQS旨在抽象基础同步操作,简化同步组件构建。 使用AQS需实现`tryAcquire(int arg)`和`tryRelease(int arg)`方法以获取和释放资源,共享模式还需实现`tryAcquireShared(int arg)`和`tryReleaseShared(int arg)`。
576 32
AQS:Java 中悲观锁的底层实现机制
|
人工智能 Java 关系型数据库
Java——SPI机制详解
SPI(Service Provider Interface)是JDK内置的服务提供发现机制,主要用于框架扩展和组件替换。通过在`META-INF/services/`目录下定义接口实现类文件,Java程序可利用`ServiceLoader`动态加载服务实现。SPI核心思想是解耦,允许不同厂商为同一接口提供多种实现,如`java.sql.Driver`的MySQL与PostgreSQL实现。然而,SPI存在缺陷:需遍历所有实现并实例化,可能造成资源浪费;获取实现类方式不够灵活;多线程使用时存在安全问题。尽管如此,SPI仍是Java生态系统中实现插件化和模块化设计的重要工具。
735 0
|
9月前
|
SQL Java 关系型数据库
Java连接MySQL数据库环境设置指南
请注意,在实际部署时应该避免将敏感信息(如用户名和密码)硬编码在源码文件里面;应该使用配置文件或者环境变量等更为安全可靠地方式管理这些信息。此外,在处理大量数据时考虑使用PreparedStatement而不是Statement可以提高性能并防止SQL注入攻击;同时也要注意正确处理异常情况,并且确保所有打开过得资源都被正确关闭释放掉以防止内存泄漏等问题发生。
441 13
|
11月前
|
人工智能 前端开发 安全
Java开发不可不知的秘密:类加载器实现机制
类加载器是Java中负责动态加载类到JVM的组件,理解其工作原理对开发复杂应用至关重要。本文详解类加载过程、双亲委派模型及常见类加载器,并介绍自定义类加载器的实现与应用场景。
393 4
|
Java 区块链 网络架构
酷阿鲸森林农场:Java 区块链系统中的 P2P 区块同步与节点自动加入机制
本文介绍了基于 Java 的去中心化区块链电商系统设计与实现,重点探讨了 P2P 网络在酷阿鲸森林农场项目中的应用。通过节点自动发现、区块广播同步及链校验功能,系统实现了无需中心服务器的点对点网络架构。文章详细解析了核心代码逻辑,包括 P2P 服务端监听、客户端广播新区块及节点列表自动获取等环节,并提出了消息签名验证、WebSocket 替代 Socket 等优化方向。该系统不仅适用于农业电商,还可扩展至教育、物流等领域,构建可信数据链条。
|
缓存 Dubbo Java
理解的Java中SPI机制
本文深入解析了JDK提供的Java SPI(Service Provider Interface)机制,这是一种基于接口编程、策略模式与配置文件组合实现的动态加载机制,核心在于解耦。文章通过具体示例介绍了SPI的使用方法,包括定义接口、创建配置文件及加载实现类的过程,并分析了其原理与优缺点。SPI适用于框架扩展或替换场景,如JDBC驱动加载、SLF4J日志实现等,但存在加载效率低和线程安全问题。
791 7
理解的Java中SPI机制
|
网络协议 物联网
VB6网络通信软件上位机开发,TCP网络通信,读写数据并处理,完整源码下载
本文介绍使用VB6开发网络通信上位机客户端程序,涵盖Winsock控件的引入与使用,包括连接服务端、发送数据(如通过`Winsock1.SendData`方法)及接收数据(利用`Winsock1_DataArrival`事件)。代码实现TCP网络通信,可读写并处理16进制数据,适用于自动化和工业控制领域。提供完整源码下载,适合学习VB6网络程序开发。 下载链接:[完整源码](http://xzios.cn:86/WJGL/DownLoadDetial?Id=20)
564 12
|
人工智能 JavaScript Java
Java反射机制及原理
本文介绍了Java反射机制的基本概念、使用方法及其原理。反射在实际项目中比代理更常用,掌握它可以提升编程能力并理解框架设计原理。文章详细讲解了获取Class对象的四种方式:对象.getClass()、类.class、Class.forName()和类加载器.loadClass(),并分析了Class.forName()与ClassLoader的区别。此外,还探讨了通过Class对象进行实例化、获取方法和字段等操作的具体实现。最后从JVM类加载机制角度解析了Class对象的本质及其与类和实例的关系,帮助读者深入理解Java反射的工作原理。
323 0
|
存储 Java 编译器
Java 中 .length 的使用方法:深入理解 Java 数据结构中的长度获取机制
本文深入解析了 Java 中 `.length` 的使用方法及其在不同数据结构中的应用。对于数组,通过 `.length` 属性获取元素数量;字符串则使用 `.length()` 方法计算字符数;集合类如 `ArrayList` 采用 `.size()` 方法统计元素个数。此外,基本数据类型和包装类不支持长度属性。掌握这些区别,有助于开发者避免常见错误,提升代码质量。
1135 1
|
缓存 运维 Java
Java静态代码块深度剖析:机制、特性与最佳实践
在Java中,静态代码块(或称静态初始化块)是指类中定义的一个或多个`static { ... }`结构。其主要功能在于初始化类级别的数据,例如静态变量的初始化或执行仅需运行一次的初始化逻辑。
536 4

热门文章

最新文章