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

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...

人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型

在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重&#xff0c;适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解&#xff0c;并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...

跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践

在电商行业蓬勃发展的当下&#xff0c;多平台运营已成为众多商家的必然选择。然而&#xff0c;不同电商平台在商品数据接口方面存在差异&#xff0c;导致商家在跨平台运营时面临诸多挑战&#xff0c;如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...

Axure Rp 11 安装、汉化、授权

Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接&#xff1a;https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...