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

news2024/11/23 19:42:39

简介

四次挥手示意图

  • 在四次挥手过程中,第一次挥手中的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.coloradmin.cn/o/1305565.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

环境变量提权

环境变量提权 借鉴文章LINUX提权之环境变量提权篇 - 知乎 (zhihu.com) 利用条件 存在一个文件,利用su权限执行,普通用户可以执行此文件,但只限制在一个目录下可以执行 利用方式 将此文件的目录添加到环境变量中 export PATH/tmp:$PATHe…

分层自动化测试的实战思考!

自动化测试的分层模型 自动化测试的分层模型,我们应该已经很熟悉了,按照分层测试理念,自动化测试的投入产出应该是一个金字塔模型。越是向下,投入/产出比就越高,但开展的难易程度/成本和技术要求就越高,但…

Linux安装Halo(个人网站)

docker安装 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun && systemctl start docker && systemctl enable docker && sudo mkdir -p /etc/docker && sudo tee /etc/docker/daemon.json <<-EOF && sudo…

开题PPT答辩复盘

目录 总体思路加粗和红体字使用研究现状之后主要研究内容讨论 总体思路 分为五个部分&#xff0c;规定在10分钟以内讲完。这次开题答辩&#xff0c;主要是要讲清楚研究背景和意义&#xff0c;国内外研究现状。因此前两部分需要花大概6分钟重点解释&#xff0c;主要研究内容用2…

提升--22---ReentrantReadWriteLock读写锁

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 ReadWriteLock----读写锁1.读写锁介绍线程进入读锁的前提条件&#xff1a;线程进入写锁的前提条件&#xff1a;而读写锁有以下三个重要的特性&#xff1a; Reentran…

jQuery遍历与删除添加节点

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

如何通过 SSH 访问 VirtualBox 的虚机

VirtualBox 是一款免费虚机软件。在用户使用它安装了 linux 以后&#xff0c;它默认只提供了控制台的管理画面。 直接使用控制台管理 Linux 没有使用诸如 putty 或者 vscode 这样的 ssh 远程管理工具方便。那么可不可以直接使用 ssh 访问 VirtualBox 上的 Linux 呢&#xff1f…

关于碰撞试验

主要参数&#xff1a; 冲击与碰撞试验的主要参数及调整方法 - 百度文库 碰撞试验的技术指标包括&#xff1a;峰值加速度、脉冲持续时间、速度变化量&#xff08;半正弦波&#xff09;、每方向碰撞次数。 加速度&#xff1a;冲击的强度&#xff0c;单位为g&#xff1b;一般为3…

【小红书运营指南2】小红书自律标签的达人分解

小红书标签的达人分解 写在最前面11.27初步想法达人分析 标签拆解&#xff08;速览版&#xff09;分析应用 思路 相关标签拆解&#xff08;详细版&#xff09;11、职场-职场干货 文化薯&#xff08;创业&#xff0c;也是专注知识付费&#xff0c;可以对标学习&#xff09;笔记画…

C++刷题 -- 哈希表

C刷题 – 哈希表 文章目录 C刷题 -- 哈希表1.两数之和2.四数相加II3.三数之和&#xff08;重点&#xff09; 当我们需要查询一个元素是否出现过&#xff0c;或者一个元素是否在集合里的时候&#xff0c;就要第一时间想到哈希法; 1.两数之和 https://leetcode.cn/problems/two…

springcloud多环境部署打包 - maven 篇

背景 在使用 springboot 和sringcloudnacos开发项目过程中&#xff0c;会有多种环境切换&#xff0c;例如开发环境&#xff0c;测试环境&#xff0c;演示环境&#xff0c;生产环境等&#xff0c;我们通过建立多个 yml 文件结合 profiles.active 属性进行环境指定&#xff0c;但…

Dockerfile创建镜像INMP+wordpress

Dockerfile创建镜像INMPwordpress 需要哪些呢&#xff1a; Nginx 172.111.0.10 docker-nginx Mysql 172.111.0.20 docker-mysql PHP 172.111.0.30 docker-PHP 开始实验&#xff1a; 创建各级目录&#xff0c;他们各自的包和配置文件必须要在同一目录下才可以生效&…

互联网加竞赛 LSTM的预测算法 - 股票预测 天气预测 房价预测

0 简介 今天学长向大家介绍LSTM基础 基于LSTM的预测算法 - 股票预测 天气预测 房价预测 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/postgraduate 1 基于 Ke…

STM32——串口实验(非中断)

需求&#xff1a; 接受串口工具发送的字符串&#xff0c;并将其发送回串口工具。 硬件接线&#xff1a; TX -- A10 RX -- A9 一定要记得交叉接线&#xff01;&#xff01; 串口配置&#xff1a; 1. 选定串口 2. 选择模式 异步通讯 3. 串口配置 4. 使用MicroLIB库 从…

PaddleOCR:超越人眼识别率的AI文字识别神器

在当今人工智能技术已经渗透到各个领域。其中&#xff0c;OCR&#xff08;Optical Character Recognition&#xff09;技术将图像中的文字转化为可编辑的文本&#xff0c;为众多行业带来了极大的便利。PaddleOCR是一款由百度研发的OCR开源工具&#xff0c;具有极高的准确率和易…

PyQt6 QStatusBar状态栏控件

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计44条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

漂亮的WPF界面 流行的一个界面,向上悬浮的窗口,终于试成功了

目前随便打开个APP&#xff0c;就可以看到一个悬浮的窗口 今天测试一下目前流行的一个界面&#xff0c;向上悬浮的窗口&#xff0c;终于试成功了。看着还不错的。

【无标题】树莓派 4B 多串口配置

0. 实验准备以及原理 0.1 实验准备 安装树莓派官方系统的树莓派 4B&#xff0c;有 python 环境&#xff0c;安装了 serial 库 杜邦线若干 屏幕或者可以使用 VNC 进入到树莓派的图形界面 0.2 原理 树莓派 4B 有 UART0&#xff08;PL011&#xff09;、UART1&#xff08;mini UAR…

AI 绘画快速开始-StableDiffusionWebui

文章目录 介绍WebUI 的安装和部署参数介绍Prompt技巧初阶Prompt&#xff1a;直接描述的精细化二阶Prompt&#xff1a;巧用标签的扩展三阶Prompt&#xff1a;负面提示词的深入应用四阶Prompt&#xff1a;文本权重调整的细化引入 LoRA&#xff1a;模型特效的创新应用 案例-生成漫…

Armv8/Armv9从入门到精通-课程介绍

通知&#xff0c;Arm二期&#xff0c;咱们也有大合集PDF了&#xff0c;共计1587页&#xff0c;还未完成&#xff0c;后续持续更新和优化中。为了方便大家阅读、探讨、做笔记&#xff0c;特意整了此合集PPT&#xff0c;为了增加标签目录&#xff0c;还特意开了福兮阅读器会员。 …