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

【JavaEE】网络编程——UDP

在这里插入图片描述
🤡🤡🤡个人主页🤡🤡🤡
🤡🤡🤡JavaEE专栏🤡🤡🤡

文章目录

  • 1.数据报套接字(UDP)
    • 1.1特点
    • 1.2编码
      • 1.2.1DatagramSocket
      • 1.2.2DatagramPacket
      • 1.2.3实现一个UDP(24*7)回显服务器
      • 1.2.4实现一个UDP客户端
      • 1.2.5实现一个UDP字典翻译服务器
  • 2.客户端与服务器的流程

1.数据报套接字(UDP)

1.1特点

  1. 无连接:数据在传输前无需建立专用通道,每一个数据包独立发送,并自行选择路径到达目的地,好比发送信息,你只要发送了信息就行,不需要对方接收。
  2. 不可靠传输:在传输数据的时候,不需要关注对方是否收到了,发送了就可以。
  3. 面向数据流:传输数据的基本单位是一个个的UDP数据报,一次读写,只能读写一个完整的UDP数据报
  4. 全双工:一条链路中,能够进行双向通信。

1.2编码

Socket api都是系统提供的,不同的系统提供的api是不一样的,但是java中对于系统的这些api进一步封装了。
UDP中的socket api 重点是两个类:DatagramSocket 和DatagramPacket

1.2.1DatagramSocket

这个类的作用可以看作"操作网卡"的遥控器,也就是对网卡进行读写操作,可以理解成像文件那样读写的形式。
提供了几个方法:
在这里插入图片描述

1.2.2DatagramPacket

这个类是描述UDP数据报,一个DatagramPacket对象相当于一个UDP数据报,一次发送一次接收就是传输了一个DatagramPacket对象。

1.2.3实现一个UDP(24*7)回显服务器

回显(Echo):客户端给服务器发送不同的请求,服务器就会返回不同的响应。但在此处回显就是客户端给服务器请求啥,服务器就响应啥,不做任何计算和业务逻辑。

public class udpEchoServer {public DatagramSocket socket = null;public udpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void  start() throws IOException {System.out.println("服务器启动!!!");while (true) {//接受客户端请求DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);socket.receive(requestPacket);//为了更好处理数据并方便打印,将接受的数据转化为字符串操作String request = new String(requestPacket.getData(),0,requestPacket.getLength());//处理客户端的请求(算术计算或者业务逻辑)String response = this.process(request);//将处理完的请求返还给客户端DatagramPacket resposePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,requestPacket.getSocketAddress());socket.send(resposePacket);//打印客户端的ip地址端口号和接收客户端的数据以及处理完客户端后的数据System.out.printf("[%s:%d] req = %s,resp = %s\n",requestPacket.getAddress(),requestPacket.getPort(),request,response);}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {udpEchoServer udpEchoServer = new udpEchoServer(9999);udpEchoServer.start();}
}

在这里插入图片描述
DatagramPacket对象表示的就是一个数据报,UDP数据报是由报头和载荷组成的,报头中的有IP地址和端口号这些都是DatagramPacket类的属性,而载荷这个类没有提供,所以需要程序猿自己去提供,所以就像和尚化缘一样,你需要自己提供一个化缘的碗,然后各家将食物放到碗中,由于数据报的本质就是一个二进制数据,所以我提供了一个字节数组来作为这个载荷存储数据。
在这里插入图片描述
从客户端接收过来的数据,经过服务器处理完之后要返还给客户端,所以需要在创建一个DatagramPacket对象来存储由服务器处理完之后的数据,再服务器发送给客户端。此时的DatagramPacket对象就不需要提供一个空白的空间,将处理完的数据放入这个对象就行,由于在接收数据的时候就记录了客户端的ip地址和端口号,所以在发送给客户端的时候只需要通过requestPacket.getSocketAddress()来获取客户端的IP地址和端口号。
在这里插入图片描述
由于服务器是固定的,所以可以直接自己去设置端口号,当服务器启动的时候端口号就被创建了。
为什么需要端口号IP地址?
要实现双方通信成功,必须要有这个四个核心指标:
源端口,源IP,目的端口,目的IP
通过这四个核心指标就可以实现双方网络通信,此处没有服务器的IP地址,是因为客户端和服务器在同一个主机上。我们可以用一个IP来表示172.0.0.1也称环回IP。

1.2.4实现一个UDP客户端

public class udpEchoClient {private DatagramSocket socket = null;private String serverIp;private int serverProt;public  udpEchoClient(String serverIp, int serverProt) throws SocketException {socket = new DatagramSocket();this.serverIp = serverIp;this.serverProt = serverProt;}public void start() throws IOException {System.out.println("客户端启动!");//1.从控制台获取字符串Scanner scanner = new Scanner(System.in);while(true) {System.out.println("请输入要发送的请求: ");String request = scanner.nextLine();//2.将输入的字符串发送给服务器,还要将发送的目标确定,IP和端口号DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length,InetAddress.getByName(serverIp), serverProt);socket.send(requestPacket);//3.从服务器读取到经过处理的响应DatagramPacket responsePackt = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePackt);//将响应打印在控制台String response = new String(responsePackt.getData(), 0, responsePackt.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {udpEchoClient udpEchoClient = new udpEchoClient("127.0.0.1",9999);udpEchoClient.start();}
}

在这里插入图片描述
从控制台接收到的字符串,requestPacket对象获取到字符串对象的引用以及长度,还有自己的IP和Prot,然后通过socket的send方法发送到服务器上。
在这里插入图片描述
从服务器接收的响应,需要创建一个responsePackt对象,并且提前创建好一个空白的字节数组来接收从服务器接收的响应。
对一些方法区分一下:
在对方法区分前,我们需要理解字节,字符,编码形式的概念
字节与字符本质上都是二进制,就是0101这种数据,因为计算机只认识0101。
字节:字节是计算机存储数据的基本单位,1个字节就是8个bit,每个位可以是0或1,表示一个字节可以表示256个不同的值.
字符:字符是表示文本信息的基本单位,根据不同的编码形式,就会有一个字符对应多少个字节就有所不同,通过编码形式可以将字符转化为字节再通过字节来表示数据,传输数据和存储数据。
编码形式:

  1. ASCII码:用于表示英文字符。它使用7位来表示128个字符(包括大小写字母、数字、标点符号和一些控制字符),就是不支持中文字符,这里就是一个字符对应一个字节
  2. Unicode(UTF8):UTF-8是一种变长的编码形式,包括全球所有书写系统的字符,兼容ASCII字符集,并且支持中文字符,包括全球所有书写系统的字符,一个字符对应1-4字节。
  3. GBK:采用变长编码,主要用于中文字符编码,一个字符对应1-2字节

方法区别一下:

  1. getBytes():得到字节数组的引用,对象是字符,这里就是将字符转化为字节来存储数据
  2. getBytes().length:得到字节数组的长度,对象是字符
  3. getData():得到的是由字符组成的字符串的引用,对象是字节,这里就是将字节转化为字符来使用数据
  4. getLength():得到的字符串的长度,对象是字节
  5. getAddress():获取IP地址,对象是DatagramPacket
  6. getPort():获取Prot端口号,对象是DatagramPacket
  7. getSocketAddress():获取到IP地址和Prot端口号,对象是DatagramPacket
  8. InetAddress.getByName():这个方法可以解析主机名并返回该主机名的 IP 地址,或者直接返回给定 IP 地址的 InetAddress 对象,得到的InetAddress 对象传给服务器,服务器通过得到这个对象就可以解析出IP地址。

1.2.5实现一个UDP字典翻译服务器

这里我们可以应用继承与多态的思想来实现这个服务器,因为这个字典翻译服务器与回显服务器本质的区别就是对响应的处理,所以我们对重复的代码继承复用,扩展需要的代码即可。

public class udpDictServer extends udpEchoServer{HashMap<String,String> map = null;public udpDictServer(int port) throws SocketException {super(port);map = new HashMap<>();map.put("server","服务");map.put("client","客户端");map.put("cat","🐱");map.put("dog","🐕");map.put("pig","🐖");}@Overridepublic String process(String request) {return map.getOrDefault(request, "该词汇没有查询到");}public static void main(String[] args) throws IOException {udpDictServer udpDictServer = new udpDictServer(9999);udpDictServer.start();}
}

实现这个字典翻译,还需要数据结构中的map,利用map中的键值对来存储数据。
在这里插入图片描述
然后具体的业务操作就只需要重写process方法即可。
在这里插入图片描述
在执行到这里的时候虽然这个this指的是父类的udpEchoServer对象,但是由于udpDictServer子类继承了udpEchoServer父类有重写了process方法,由于多态的特性执行的process方法其实是子类的process方法。

2.客户端与服务器的流程

  1. 从控制台获取数据
  2. 客户端将数据发送到服务器
  3. 服务器接收客户端发送过来的数据
  4. 计算响应
  5. 服务器将计算好的响应发送给客户端
  6. 客户端接收服务器发送的响应
  7. 将从客户端接收服务器发送的响应打印在控制台

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 工程化-vue3+ts:代码检测工具 ESLint
  • C++入门到进阶(图文详解,持续更新中)
  • Qt学生管理系统(付源码)
  • 解析 unstructured pdfminer_utils.py rect_to_bbox 坐标转换函数
  • IOC、DI<4> Unity、AOP、MVCAOP、UnityAOP 区别
  • python编程实例 输出两个数之间的素数
  • Vue中实现在线画流程图实现
  • 解决后端限制导致前端配置跨域仍请求失败报504的问题
  • 如何在 Ubuntu 16.04 上安装和配置 Zabbix 以安全监控远程服务器
  • 应急响应-战后溯源反制社会工程学
  • C++ 实现图书馆资料管理系统
  • lvs集群、NAT模式和DR模式、keepalive
  • wifi中的PSR技术
  • Java Stream API详解:高效处理集合数据的利器
  • 休息时间c++
  • 【comparator, comparable】小总结
  • C++入门教程(10):for 语句
  • Codepen 每日精选(2018-3-25)
  • ES6核心特性
  • exports和module.exports
  • Java读取Properties文件的六种方法
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • windows下mongoDB的环境配置
  • 关于Java中分层中遇到的一些问题
  • 关于List、List?、ListObject的区别
  • 入门级的git使用指北
  • 软件开发学习的5大技巧,你知道吗?
  • 使用 @font-face
  • 网页视频流m3u8/ts视频下载
  • 用mpvue开发微信小程序
  • mysql面试题分组并合并列
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • ​​​​​​​​​​​​​​Γ函数
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • # include “ “ 和 # include < >两者的区别
  • #define,static,const,三种常量的区别
  • (42)STM32——LCD显示屏实验笔记
  • (7)STL算法之交换赋值
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (附源码)spring boot基于小程序酒店疫情系统 毕业设计 091931
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (转)3D模板阴影原理
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • .babyk勒索病毒解析:恶意更新如何威胁您的数据安全
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .net SqlSugarHelper
  • .net wcf memory gates checking failed
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)