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,有了更深入的了解。

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

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

相关文章

LV.13 D4 uboot使用 学习笔记

一、uboot环境变量命令 1.1 uboot模式 自启动模式 uboot 启动后若没有用户介入,倒计时结束后会自动执行自启动环境变量 (bootcmd) 中设置的命令(一般作加载和启动内核) 交互模式 倒计时结束之前按下任意按键 uboot 会进…

异地现场工控设备,如何实现远程配置、调试?

南京某企业专注于工业物联领域,在相关项目中往往会在各个点位部署基于Linux系统的中控主机,实现各类物联设备信息的采集、汇总。但是,由于各点位分散多地,且数量达到了上百个,虽然中控主机具备4G物联网接入能力&#x…

【Vue】elementUI表格,导出Excel

系列文章 【Vue】vue增加导航标签 本文链接:https://blog.csdn.net/youcheng_ge/article/details/134965353 【Vue】Element开发笔记 本文链接:https://blog.csdn.net/youcheng_ge/article/details/133947977 【Vue】vue,在Windows IIS平台…

设计模式——策略模式(Strategy Pattern)

概述 策略模式又叫政策模式,是一种对象行为型模式。它是将定义的算法家族分别封装起来,让它们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户。策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为和环…

小程序使用Nodejs作为服务端,Nodejs与与MYSQL数据库相连

小程序使用Nodejs作为服务端,Nodejs与MYSQL数据库相连 一、搭建环境二、配置Nodejs三、与小程序交互四、跨域处理/报错处理五、nodejs连接mysql数据库六、微信小程序连接nodejs报错七、小程序成功与服务端相连,且能操作数据库一、搭建环境 新建空文件夹:Win + R进入cmd命令界…

Unity 控制刚体的移动与旋转的方法

在场景创建一个Cube,并添加刚体,如图: 编写脚本: using System.Collections; using System.Collections.Generic; using UnityEngine;[RequireComponent(typeof(Rigidbody))] public class RibRotate : MonoBehaviour {//private Vector3 mo…

C语言----文件操作(二)

在上一篇文章中我们简单介绍了在C语言中文件是什么以及文件的打开和关闭操作,在实际工作中,我们不仅仅是要打开和关闭文件,二是需要对文件进行增删改写。本文将详细介绍如果对文件进行安全读写。 一,以字符形式读写文件&#xff…

中通单号查询,中通快递物流查询,对需要的单号进行备注

批量查询中通快递单号的物流信息,对需要的单号进行备注。 所需工具: 一个【快递批量查询高手】软件 中通快递单号若干 操作步骤: 步骤1:运行【快递批量查询高手】软件,并登录 步骤2:点击主界面左上角的“…

iOS使用CoreText完成txt阅读器

CoreText是一个高效处理字符和字形转换和进行文字排版的框架,API基于C语言。 常见的CoreText类介绍 (1)、CFAttributedStringRef 属性字符串,用于存储需要绘制的文字字符和字符属性 (2)、CTFramesetterR…

JVM学习之JVM概述

JVM的整体结构 Hotspot VM是目前市面上高性能虚拟机代表作之一 它采用解释器与即时编译器并存的架构 在今天,Java程序的运行性能已经达到了可以和C/C程序一较高下的地步 Java代码执行流程 具体图为 JVM架构模型 Java编译器输入的指令流基本上是一种基于 栈的指令…

大创项目推荐 垃圾邮件(短信)分类算法实现 机器学习 深度学习

文章目录 0 前言2 垃圾短信/邮件 分类算法 原理2.1 常用的分类器 - 贝叶斯分类器 3 数据集介绍4 数据预处理5 特征提取6 训练分类器7 综合测试结果8 其他模型方法9 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 垃圾邮件(短信)分类算…

Github与Gitlab

学习目标 能够使用GitHub创建远程仓库并使用能够安装部署GitLab服务器能够使用GitLab创建仓库并使用掌握CI/CD的概念掌握蓝绿部署, 滚动更新,灰度发布的概念 GitHub是目前最火的开源项目代码托管平台。它是基于web的Git仓库,提供公有仓库和私有仓库,但私…

Amortized Bootstrapping of LWE:使用 BFV 打包处理

参考文献: [AP13] Alperin-Sheriff J, Peikert C. Practical bootstrapping in quasilinear time[C]//Annual Cryptology Conference. Berlin, Heidelberg: Springer Berlin Heidelberg, 2013: 1-20.[MS18] Micciancio D, Sorrell J. Ring packing and amortized F…

下午好~ 我的论文【CV边角料】(第三期)

文章目录 CV边角料Pixel ShuffleSENetCBAMGlobal Context Block (GC)Criss-Cross Attention modules (CC) CV边角料 Pixel Shuffle Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network pixelshuffle算法的实现流…

初识GroovyShell

文章目录 前言一、GroovyShell二、maven三、解决方案四、关键代码4.1 数据库配置表(pg)4.2 入参4.3 分页查询 总结 前言 项目背景:查询多个表的数据列表和详情,但不想创建过多的po、dao、resp等项目文件。 一、GroovyShell Apache Groovy是一种强大的…

rabbitmq-windows安装使用-简易后台界面-修改密码

文章目录 1.下载2.安装3.安装 RabbitMQ4.后台访问5.修改密码 1.下载 将erlang运行时和rabbitmq-windows版本,上传在csdn,下载链接。https://download.csdn.net/download/m0_67316550/88633443 2.安装 右键,以管理员身份运行rabbitmq。启动…

如何安装LUT预设?达芬奇/FCP/PR怎么安装LUT预设.cube格式文件的教程

在下载的LUT调色预设压缩文件包中,通常两个包含不同格式的LUT文件: .cube 和 .xmp 包含的 .cube 文件几乎与主流的视频编辑和色彩校正软件兼容,并且还可以在 Adobe Photoshop 等一些照片应用程序中使用。如果主要是将这些 LUT 用于视频剪辑项…

Redis-数据结构

参考资料 极客时间Redis(亚风) Redis数据结构 SDS sds(Simple Dynamic String) 字符串接结构体: struct --attribute_- ((-_packed__)) sdshdr8{uint8_t len;/* buf已保祥的字符串字节数,不包含结束标示*/uint8_t alloc&#…

day02-报表技术POI

1、基于模板导出列表数据 1.1、需求 按照以下样式导出excel 1.2、思路 首先准备一个excel模板,这个模板把复杂的样式和固定的内容先准备好并且放入到项目中,然后读取到模板后向里面放入数据。 1.3、实现 第一步:准备一个excel作为导出的…

AI 编程助手 Copilot:从对话中分析程序性能

大家好,我是木川 一、介绍 GitHub Copilot 是 GitHub 和 OpenAI 合作开发的一个 AI 辅助编程工具 官网地址:https://github.com/features/copilot 官方文档:https://docs.github.com/copilot 分析程序性能在对话功能中有提到 二、安装 在 VSC…