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

Java网络编程,使用UDP实现TCP(二), 实现数据传输过程

简介:

经过了三次握手过程,我们的服务端和客户端已经建立了连接。我们接下来需要做的就是数据的传输。

主要步骤:

  1. 数据发送:客户端或服务器将数据打包成一个或多个数据段,每个数据段都有一个序列号(SEQ)和确认号(ACK)。

  2. 数据接收:接收方接收到数据段后,将根据数据段的序列号(SEQ)进行排序,以确保数据的有序性。

  3. 确认接收:接收方会为每个接收到的数据段发送一个确认(ACK)。这个确认包含了确认号(ACK),该确认号是接收方期望接收的下一个数据段的序列号,也就是最后一个接收到的数据段的序列号加1。

  4. 丢包重传:如果发送方在一定时间内没有接收到某个数据段的确认,它会认为该数据段已经丢失,并进行重传。

  5. 流量控制:接收方可以使用窗口大小字段来控制发送方的发送速度,以防止自己被大量的数据淹没。

  6. 拥塞控制:如果网络发生拥塞,TCP会降低数据的发送速度,以减少网络的拥塞程度。(未实现)

所以在数据传输段过程中,每一段都需要Seq(序列号),ACK(确认号)

实现过程:

  1. 确认号(ACK)是基于之前接收到的最后一个数据包的序列号+1。也就是说,ACK的值是接收方期望接收的下一个数据包的序列号。这是因为,在TCP协议中,ACK的值总是等于接收方已经成功接收的最后一个数据包的序列号+1。
  2. 例如,假设在三次握手的过程中,客户端发送给服务器的最后一个ACK是101(这是第三次握手的ACK),那么在数据传输开始时,如果服务器是第一个发送数据的话,服务器发送的第一个数据包的序列号应该是101,而客户端回复的ACK就应该是102,表示客户端已经接收到了序列号为101的数据包,期望接收的下一个数据包的序列号是102。

服务端发送数据到客户端

  • 注意由于数据的传输是双向的,所以在发送后可以接收客户端发来的数据。
  • 在接收数据后,我们在服务端需要进行超时判断,如若超时会进行超时重传。超时判断我们使用了 setSoTimeout() 方法。
    • 关于超时的时间,根据《TCP/IP详解》卷二 的计时器篇中可知,超时时间严苛来说,需要考虑发送端到接收端接收数据时间接收端数据处理时间接收端发送确认消息到客服端时间。超时时间的选择应该是多次数据传输花费时间的均值
  • 在《TCP/IP详解》卷二 的 tcp 篇详细中规定了数据重传不能超过三次,这里我使用了retryCount这个计数器来计数。
//数据传输开始System.out.println("====================");System.out.println("数据发送...");String SeqD1 = String.valueOf(connectionMarks.getSeq());String ACKD1 = String.valueOf(Integer.parseInt(strArr3[1]) + 1);String dataMsg = SeqD1 + " " + "我是马尔咖里斯,我是不朽的!" + " " + ACKD1;byte[] datasD1 = dataMsg.getBytes();DatagramPacket datagramPacketD1 = new DatagramPacket(datasD1, 0,datasD1.length, new InetSocketAddress("localhost",8888));int maxRetries = 3; // 最大重试次数int retryCount = 0; // 当前重试次数boolean success = false; // 是否成功标志while (!success && retryCount < maxRetries) {try {// 设置超时时间datagramSocket.setSoTimeout(50000);// 发送数据datagramSocket.send(datagramPacket);// 接收响应byte[] buffer = new byte[1024];DatagramPacket responsePacket = new DatagramPacket(buffer, buffer.length);datagramSocket.receive(responsePacket);// 处理响应String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println("接收到响应:" + response);// 设置成功标志success = true;} catch (java.net.SocketTimeoutException e) {// 超时后重新发送数据retryCount++;System.out.println("超时,进行第 " + retryCount + " 次重试");} catch (IOException e) {// 处理其他异常e.printStackTrace();}}if (!success) {System.out.println("重试次数超过最大限制,操作失败");}

客户端发送数据到服务端

注意:在tcp三次握手后数据段的传输也需要添加ACK,和Seq,如前文所述。这里为了便于实现在传回数据时只写了数据返回 “收到消息” 是不符合规定的,需要修改。

 System.out.println("====================");System.out.println("开始接收数据段...");byte[] bytes1 = new byte[1024];DatagramPacket datagramPacketD1 = new DatagramPacket(bytes1, bytes1.length);datagramSocket.receive(datagramPacketD1);String receiveMsg = new String(datagramPacketD1.getData(), 0, datagramPacketD1.getLength());System.out.println("接收到的数据段为:" + receiveMsg);String[] split = receiveMsg.split(" ");String SeqD1 = split[0];System.out.println("====================");System.out.println("数据消息确认返回");String replyMsg = "收到消息";clientMsg.sendMsg(replyMsg, datagramSocket);

相关文章:

  • C语言—每日选择题—Day46
  • Redux Toolkit(RTK)在React tsx中的使用
  • UDP群聊
  • Java网络编程,对使用UDP实现TCP(一)三次握手实现的补充
  • 华为OD机试 - 数据单元的变化替换(Java JS Python C)
  • 在idea中使用maven创建dynamic web project
  • 4-Docker命令之docker export
  • Redis KEY*模糊查询导致速度慢、阻塞其他 Redis 操作
  • 破晓6G新时代:迈向新一代星地融合的高速测试解决方案
  • Mysql的多表联合查询
  • OpenAI 承认 ChatGPT 最近确实变懒,承诺修复问题
  • 基于Maven构建OSGI应用(Maven和OSGI结合)
  • 为什么现在是学习 Rust 的最佳时机
  • js根据数组对象中的某个值去重
  • Android audio设置投屏和喇叭双输出
  • 深入了解以太坊
  • Android开源项目规范总结
  • CentOS7简单部署NFS
  • ES6核心特性
  • express如何解决request entity too large问题
  • HTTP 简介
  • k8s 面向应用开发者的基础命令
  • Laravel核心解读--Facades
  • markdown编辑器简评
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 规范化安全开发 KOA 手脚架
  • 回顾2016
  • 如何合理的规划jvm性能调优
  • 硬币翻转问题,区间操作
  • 正则表达式
  • 中文输入法与React文本输入框的问题与解决方案
  • 字符串匹配基础上
  • ​力扣解法汇总946-验证栈序列
  • #《AI中文版》V3 第 1 章 概述
  • #13 yum、编译安装与sed命令的使用
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (三)Honghu Cloud云架构一定时调度平台
  • (学习日记)2024.01.09
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (转)Windows2003安全设置/维护
  • .NET Framework杂记
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)
  • .NET中winform传递参数至Url并获得返回值或文件
  • .skip() 和 .only() 的使用
  • [20171102]视图v$session中process字段含义
  • [AutoSAR 存储] 汽车智能座舱的存储需求
  • [BZOJ1060][ZJOI2007]时态同步 树形dp
  • [BZOJ2208][Jsoi2010]连通数
  • [C#]winform部署yolov9的onnx模型
  • [C#7] 1.Tuples(元组)
  • [CF482B]Interesting Array
  • [cocos2d-x]关于CC_CALLBACK