当前位置: 首页 > 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…...

嵌入式Linux驱动开发全攻略

1. 嵌入式Linux驱动开发全景解析 从事嵌入式开发多年&#xff0c;我深刻体会到驱动开发是整个嵌入式系统中最为关键也最具挑战性的部分。它像一座桥梁&#xff0c;连接着冰冷的硬件和灵活多变的软件世界。今天&#xff0c;我将从实际工程角度&#xff0c;系统梳理嵌入式Linux驱…...

如何从视频中高效提取幻灯片:智能工具应用指南

如何从视频中高效提取幻灯片&#xff1a;智能工具应用指南 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 你是否曾遇到这样的困扰&#xff1a;参加线上会议后想整理演示文稿&#x…...

软考培训机构防套路手册:从师资甄别到合同陷阱的7个关键检查点

软考培训机构防套路手册&#xff1a;从师资甄别到合同陷阱的7个关键检查点 第一次报考软考的考生往往会被培训机构"包过""名师押题"的广告吸引&#xff0c;却不知道这个行业存在多少精心设计的消费陷阱。去年某考生花费6800元报名"保过班"&…...

判断当前页面是否以「添加到主屏幕」应用形态启动 (快捷方式\APP、套壳包等启动)

这里写自定义目录标题判断当前页面是否以「添加到主屏幕」应用形态启动判断当前页面是否以「添加到主屏幕」应用形态启动 /*** 判断当前页面是否以「添加到主屏幕」应用形态启动* - iOS Safari: navigator.standalone* - 标准 PWA: display-mode 为 standalone/fullscreen/min…...

覆盖更远、组网更稳:基于 EFR32BG21 的智能家居与物联网 BLE Mesh 无线模块方案

智能家居与物联网设备越来越多&#xff0c;但真正决定体验上限的往往不是“有没有连上网”&#xff0c;而是信号能不能到、掉线后能不能自愈、多设备同时在线是否还稳定。单靠点对点蓝牙&#xff0c;很容易在隔墙、远距离、多节点场景里碰到瓶颈&#xff1b;而把低功耗蓝牙与 M…...

基于yolov26的桃子成熟度检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面

基于 PyQt5 和 YOLO26 的目标检测桌面应用程序&#xff0c;支持图片、视频和摄像头实时检测。 功能特性 图片检测&#xff1a;支持图片检测视频检测&#xff1a;支持视频文件实时检测与播放摄像头检测&#xff1a;支持实时摄像头视频流检测模型切换&#xff1a;支持加载不同的 …...

如何利用 three.ar.js 快速实现 3D 模型加载与 AR 场景渲染

如何利用 three.ar.js 快速实现 3D 模型加载与 AR 场景渲染 【免费下载链接】three.ar.js A helper three.js library for building AR web experiences that run in WebARonARKit and WebARonARCore 项目地址: https://gitcode.com/gh_mirrors/th/three.ar.js three.ar…...

若依(ruoyi)RuoYiApp版—页面

ruoyiApp中的页面是一个符合vue规范的文件&#xff0c;如果你熟悉vue&#xff0c;这里将非常快速上手。 1.如何新增页面 uni-app中的页面&#xff0c;默认保存在工程根目录下的pages目录下。 每次新建页面&#xff0c;均需在pages.json中配置pages列表&#xff1b;未在pages.js…...

tao-8k性能优化小技巧:如何提升向量化与检索速度

tao-8k性能优化小技巧&#xff1a;如何提升向量化与检索速度 1. 理解tao-8k的性能瓶颈 1.1 模型架构特点 tao-8k作为支持8192长度上下文的嵌入模型&#xff0c;其核心优势在于长文本处理能力。然而&#xff0c;这种能力也带来了独特的性能挑战&#xff1a; 计算复杂度&…...

别再手动改IP了!用NI-USRP Configuration Utility快速配置USRP-2954与LabVIEW通信(附避坑指南)

告别手动配置&#xff1a;NI-USRP Configuration Utility高效连接USRP-2954与LabVIEW全攻略 当第一次将USRP-2954设备连接到电脑时&#xff0c;许多工程师都会遇到一个看似简单却令人头疼的问题——IP配置。设备明明已经通过网线连接&#xff0c;但在LabVIEW中却始终无法识别&…...