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

Java网络编程,使用UDP实现TCP(三), 基本实现四次挥手

简介

四次挥手示意图

  • 在四次挥手过程中,第一次挥手中的Seq为本次挥手的ISN, ACK为 上一次挥手的 Seq+1,即最后一次数据传输的Seq+1。
  • 挥手信息由客户端首先发起。

实现步骤:

下面是TCP四次挥手的步骤:

  1. 第一次挥手(FIN):主动关闭方发送一个带有FIN(Finish)标志的TCP报文段给被动关闭方,表示主动关闭方已经没有数据要发送了。

  2. 第二次挥手(ACK):被动关闭方接收到第一次挥手的TCP报文段后,发送一个带有ACK(Acknowledgment)和确认序号的TCP报文段作为响应,表示已经收到了关闭请求。

  3. 第三次挥手(FIN):被动关闭方发送一个带有FIN标志的TCP报文段给主动关闭方,表示被动关闭方也没有数据要发送了。

  4. 第四次挥手(ACK):主动关闭方接收到第三次挥手的TCP报文段后,发送一个带有ACK和确认序号的TCP报文段作为响应,表示已经收到了关闭请求。

在完成这四次挥手之后,TCP连接就正式关闭了。需要注意的是,每一次挥手都需要对方的确认才能进行下一步操作,这样可以确保双方都知道连接已经关闭,并且保证数据的完整性和可靠性。

这个过程可以简化为以下步骤:

  1. 主动关闭方发送FIN报文段。
  2. 被动关闭方接收到FIN后,发送ACK报文段作为确认。
  3. 被动关闭方发送FIN报文段。
  4. 主动关闭方接收到FIN后,发送ACK报文段作为确认。

这样,TCP连接就完成了关闭过程。

修改说明:

我将客户端的发送消息和服务端的接收消息做了一些简单的封装:

客户端:

    public void sendMsg(String dataMsg, DatagramSocket datagramSocket) throws IOException {byte[] bytes = dataMsg.getBytes();DatagramPacket datagramPacketMsg = new DatagramPacket(bytes, 0,bytes.length, new InetSocketAddress("localhost",9999));datagramSocket.send(datagramPacketMsg);}

服务端:

//接收数据public String receive(DatagramSocket datagramSocket, int time1, int time2) throws IOException {//设置超时时间datagramSocket.setSoTimeout(time1);//创建数据包,用于接收数据byte[] bytes3 = new byte[1024];DatagramPacket datagramPacket3 = new DatagramPacket(bytes3, bytes3.length);datagramSocket.receive(datagramPacket3);//停止计时器datagramSocket.setSoTimeout(time2);String s3 = new String(datagramPacket3.getData(), 0, datagramPacket3.getLength());return s3;}

 

第一次挥手

客户端发送关闭请求:

 //四次挥手,关闭连接System.out.println("====================");System.out.println("四次挥手:");System.out.println("第一次挥手: 客户端 -> 服务端");System.out.println("数据发送...");connectionMarks.setFinMark(2);String finMark = String.valueOf(connectionMarks.getFinMark());connectionMarks.setACKMark(1);String ACKFin = String.valueOf(connectionMarks.getACKMark());String SeqFin = String.valueOf(connectionMarks.getSeq());String ACKS1 = String.valueOf(Integer.parseInt(SeqD1) + 1);String dataF1 = finMark + "/" + ACKFin + " " + SeqFin + " " + ACKS1;clientMsg.sendMsg(dataF1, datagramSocket);

服务端接收数据:

 //四次握手//第一次System.out.println("====================");String receiveB1 = serverMsg.receive(datagramSocket, 0, 0);System.out.println("接收到的数据段为:" + receiveB1);String[] s1 = receiveB1.split(" ");String[] splitS1 = s1[0].split("/");if (!(splitS1[0].equals("2")|| splitS1[1].equals("1")|| s1[2].equals(String.valueOf(Integer.parseInt(SeqD1) + 1)))){throw new WrongConnectionException("非本次连接");}

第二次挥手

服务端发送第一次挥手的ACK

//第二次System.out.println("====================");System.out.println("服务端 -> 客户端");System.out.println("数据发送...");String SeqB2 = s1[2];String ACKB2 = String.valueOf(Integer.parseInt(s1[1]) + 1);connectionMarks.setACKMark(1);String ackMarkB = String.valueOf(connectionMarks.getACKMark());String dataMsgB2 = ackMarkB+ " " + SeqB2 + " " + ACKB2;byte[] datasB2 = dataMsgB2.getBytes();DatagramPacket datagramPacketB2 = new DatagramPacket(datasB2, 0,datasB2.length, new InetSocketAddress("localhost",8888));//调用对象发送数据datagramSocket.send(datagramPacketB2);

客户端接收

 System.out.println("====================");System.out.println("开始接收数据段...");byte[] bytesB2 = new byte[1024];DatagramPacket datagramPacketB2 = new DatagramPacket(bytesB2, bytesB2.length);datagramSocket.receive(datagramPacketB2);String receiveMsgB2 = new String(datagramPacketB2.getData(), 0, datagramPacketB2.getLength());System.out.println("接收到的数据段为:" + receiveMsgB2);

 

第三次挥手

服务端发送请求关闭给客户端

System.out.println("====================");System.out.println("服务端 -> 客户端");System.out.println("数据发送...");String SeqB3 = SeqB2;String FinMark = splitS1[0];String ACKB3 = ACKB2;String dataMsgB3 = FinMark + "/" + ackMarkB+ " " + SeqB3 + " " + ACKB3;byte[] datasB3 = dataMsgB3.getBytes();DatagramPacket datagramPacketB3 = new DatagramPacket(datasB3, 0,datasB3.length, new InetSocketAddress("localhost",8888));//调用对象发送数据datagramSocket.send(datagramPacketB3);

 客户端接收数据,需要校验,如果收到为关闭请求,则发送ACK给服务端

 System.out.println("====================");System.out.println("开始接收数据段...");byte[] bytesB3 = new byte[1024];DatagramPacket datagramPacketB3 = new DatagramPacket(bytesB3, bytesB3.length);datagramSocket.receive(datagramPacketB3);String receiveMsgB3 = new String(datagramPacketB3.getData(), 0, datagramPacketB3.getLength());System.out.println("接收到的数据段为:" + receiveMsgB3);String[] splitB3 = receiveMsgB3.split(" ");String[] split2 = splitB3[0].split("/");if (!(split2[0].equals("2")|| split2[1].equals("1")||splitB3[1].equals(ACKS1)||splitB3[2].equals(String.valueOf(Integer.parseInt(SeqFin) + 1)))){throw new WrongConnectionException("非本次连接");}

第四次挥手

客户端接收并发送第三次挥手的ACK给服务端

System.out.println("====================");System.out.println("第四次挥手: 客户端 -> 服务端");System.out.println("数据发送...");String ackMark4 = ACKFin;String SeqB4 = SeqFin;String ACKB4 = String.valueOf(Integer.parseInt(ACKS1) + 1);String dataB4 = ackMark4 + " " + SeqB4 + " " + ACKB4;clientMsg.sendMsg(dataB4, datagramSocket);//关闭流datagramSocket.close();

客户端接收到ACK并且关闭 

System.out.println("====================");String receiveB4 = serverMsg.receive(datagramSocket, 0, 0);System.out.println("接收到的数据段为:" + receiveB4);//关闭流datagramSocket.close();

完成总结:

  • 基本完成了UDP实现TCP,但仍有欠缺。
  • 实现过程中代码的复用过高,没有进行有效的方法封装。
  • 代码不够成熟,还由一些不完善的地方,没有实现MTU机制。
  • 对UDP和TCP,有了更深入的了解。

相关文章:

Java网络编程,使用UDP实现TCP(三), 基本实现四次挥手

简介 四次挥手示意图 在四次挥手过程中,第一次挥手中的Seq为本次挥手的ISN, ACK为 上一次挥手的 Seq1,即最后一次数据传输的Seq1。挥手信息由客户端首先发起。 实现步骤: 下面是TCP四次挥手的步骤: 第一次挥手&…...

“百里挑一”AI原生应用亮相,百度智能云千帆AI加速器首个Demo Day来了!

作者简介: 辭七七,目前大二,正在学习C/C,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: 七七的闲谈 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖&#x1f…...

PyTorch深度学习实战(25)——自编码器

PyTorch深度学习实战(25)——自编码器 0. 前言1. 自编码器2. 使用 PyTorch 实现自编码器小结系列链接 0. 前言 自编码器 (Autoencoder) 是一种无监督学习的神经网络模型,用于数据的特征提取和降维,它由一个编码器 (Encoder) 和一…...

靠谱的车- 华为OD统一考试(C卷)

靠谱的车- 华为OD统一考试(C卷) OD统一考试(C卷) 分值: 100分 题解: Java / Python / C 题目描述 程序员小明打了一辆出租车去上班。出于职业敏感,他注意到这辆出租车的计费表有点问题&#xf…...

Apache Flink(十一):Flink集群部署-Standalone集群部署

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录 1. 节点划分...

vue的组件传值

Vue中组件之间的数据传递可以使用props和$emit来实现。 1.使用props传递数据&#xff1a;父组件可以通过子组件的props属性向子组件传递数据。 父组件中&#xff1a; <template><div><child-component :message"parentMessage"></child-comp…...

ue5材质预览界面ue 变黑

发现在5.2和5.1上都有这个bug 原因是开了ray tracing引起的&#xff0c;这个bug真是长时间存在&#xff0c;类似的bug还包括草地上奇怪的影子和地形上的影子等等 解决方法也很简单&#xff0c;就是关闭光追&#xff08;不是…… 就是关闭预览&#xff0c;在材质界面preview sc…...

【SpringCloud篇】Eureka服务的基本配置和操作

文章目录 &#x1f339;简述Eureka&#x1f6f8;搭建Eureka服务⭐操作步骤⭐服务注册⭐服务发现 &#x1f339;简述Eureka Eureka是Netflix开源的一个基于REST的服务治理框架&#xff0c;主要用于实现微服务架构中的服务注册与发现。它由Eureka服务器和Eureka客户端组成&#…...

模拟目录管理 - 华为OD统一考试(C卷)

OD统一考试(C卷) 分值: 200分 题解: Java / Python / C++ 题目描述 实现一个模拟目录管理功能的软件,输入一个命令序列,输出最后一条命令运行结果。 支持命令: 1)创建目录命令: mkdir 目录名称,如mkdir abc为在当前目录创建abc目录,如果已存在同名目录则不执行任何操作…...

卷王开启验证码后无法登陆问题解决

问题描述 使用 docker 部署&#xff0c;后台设置开启验证&#xff0c;重启服务器之后&#xff0c;docker重启&#xff0c;再次访问系统&#xff0c;验证码获取失败&#xff0c;导致无法进行验证&#xff0c;也就无法登陆系统。 如果不了解卷王的&#xff0c;可以去官网看下。…...

【知识】如何区分图论中的点分割和边分割

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 以下两个概念在现有中文博客下非常容易混淆&#xff1a; edge-cut(边切割) vertex-partition(点分割)vertex-cut(点切割) edge-partition(边分割) 实际上&#xff0c;初看中文时&#xff0c;真的会搞不清楚。但…...

【华为鸿蒙系统学习】- HarmonyOS4.0开发工具和环境配置问题总结|自学篇

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 官方链接 HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 安装教程 &#xff08;…...

第78讲:MySQL数据库Binlog日志的核心概念与应用案例

文章目录 1.Binlog二进制日志的基本概念1.1.什么是Binlog二进制1.2.Binlog日志的三种记录格式1.3.Binlog日志中Event事件的概念 2.开启MySQL的Binlog二进制日志3.查看Binlog二进制日志中的Event事件信息3.1.查看当前数据库有那些Binlog日志3.2.产生一些DDL/DML语句3.3.观察Binl…...

MinGW编译Python至pyd踩坑整理

title: MinGW编译Python至pyd踩坑整理 tags: [Python,CC] categories: [开发记录,Python] date: 2023-12-12 13:48:20 description: sidebar: [‘toc’, ‘related’,‘recent’] 注意需要魔法 用scoop自动安装配置MinGw 需要魔法&#xff0c;不需要手动配置mingw scoop in…...

计算机毕业设计 基于SpringBoot的乡村政务办公系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

命令行参数(C语言)

目录 什么是命令行参数 main函数的可执行参数 不传参打印 传参打印 IDE传参 cmd传参 命令行参数的应用&#xff08;文件拷贝&#xff09; 什么是命令行参数 概念&#xff1a;命令行参数指的是在运行可执行文件时提供给程序的额外输入信息。它们通常以字符串形式出现&am…...

WT2003H4-16S语音芯片:扭蛋机新潮音乐,娱乐升级无限

在扭蛋机的乐趣世界里&#xff0c;唯创知音的WT2003H4-16S语音芯片&#xff0c;作为MP3音乐解码播放IC&#xff0c;为扭蛋机带来了更智能、更富有趣味的音乐体验&#xff0c;为玩家打开了娱乐升级的无限可能。 1. 机启音乐&#xff0c;欢迎扭蛋之旅 扭蛋机启动时&#xff0c;…...

Go 语言开发工具

Go 语言开发工具 VSCode VScode 安装教程参见&#xff1a;https://www.kxdang.com/topic//w3cnote/vscode-tutorial.html 然后我们打开 VSCode 的扩展&#xff08;CtrlShiftP&#xff09;&#xff1a; 搜索 go&#xff1a; 点击安装&#xff0c;安装完成后我们就可以使用代码…...

神经网络是如何工作的? | 京东云技术团队

作为一名程序员&#xff0c;我们习惯于去了解所使用工具、中间件的底层原理&#xff0c;本文则旨在帮助大家了解AI模型的底层机制&#xff0c;让大家在学习或应用各种大模型时更加得心应手&#xff0c;更加适合没有AI基础的小伙伴们。 一、GPT与神经网络的关系 GPT想必大家已…...

C++ Qt开发:RadioButton单选框分组组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍QRadioButton单选框组件以及与之交互的QButto…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...