JavaEE——网络编程(UDP套接字编程)

文章目录

  • 一、简单理解Socket 套接字
  • 二、UDP 数据报套接字编程
  • 三、编写简单的 UDP 版本服务器客户端
    • 1. 编写 UDP 版本的回显服务器
      • 回显服务器整体代码罗列
    • 2. 编写 UDP 版本的回显客户端
      • 回显客户端整体代码罗列
  • 四、总结与代码运行结果解释

一、简单理解Socket 套接字

概念: Socket 套接字就是操作系统给应用程序提供的网络编程 API。

我们可以认为 socket api 是和传输层密切相关的。

我们知道,在传输层中,提供了两个最核心的协议,UDP TCP。
因此,socket api 中也提供了两种风格。UDP TCP。

在这里我们简单认识一下 UDP 和 TCP

  • UDP: 无连接 不可靠传输 面向数据报 全双工。
  • TCP: 有连接 可靠传输 面向字节流 全双工。

解释 有连接 / 无连接

例:
打电话就是有连接的,需要建立了才能通信。建立连接需要对方来 “接受”
发短信,就是无连接的,直接发送即可无需接受。

解释 可靠传输 / 不可靠传输

在这里,对于可靠传输的定义是:发送方的数据到底是不是发送过去了,还是丢了

所以,在这里:
打电话是一个可靠传输。
发短信是一个不可靠传输。
但要注意的是,可靠不可靠,与有没有连接没有任何关系

解释 面向字节流 / 面向数据报

面向字节流: 数据传输和文件读写类似,是“流式”的。
面向数据报: 数据传输以一个个“数据报”为单位。(一个数据报可能为若干个字节,带有一定的格式)。

解释 全双工

即就是一个通信通道,可以双向传输。(既可以发送,也可以接收)

对应的 半双工 就是指只可以单向传输信息。
至于如何传递信息,与用户的 路由器,交换机配置有关。如图:
在这里插入图片描述

二、UDP 数据报套接字编程

这里给出了两个类用来操作:

  • DatagramSocket

使用这个类表示一个 socket 对象。
在操作系统中,是将这个 socket 对象当成一个文件来处理的。

对于普通文件,对应的硬件设备是 硬盘。 对于socket 文件,对应的硬件设备是 网卡

拥有了 socket 对象就可以与另一台主机进行通信。如果要和多个不同主机交互,就需要创建多个 socket 对象。

DatagramSocket 构造方法:
在这里插入图片描述
在这里就可以看出来,本质上不是 进程 和 端口 建立联系,而是进程中的 socket 对象和 端口 建立联系

DatagramSocket 方法:
在这里插入图片描述
对于 void receive(DatagramPacket p) 方法:
在此处传入的相当于一个空对象,receive 方法内部,会对参数的空对象进行内容填充。从而构造出结果数据。(构造出一个数据报)

  • DatagramPacket

该套接字 API 表示的是 UDP 中传输的一个报文。构造这个对象可以将指定的具体数据传递进去。

DatagramPacket 构造方法:

在这里插入图片描述
DatagramPacket 方法:

在这里插入图片描述

三、编写简单的 UDP 版本服务器客户端

文章中详细解释的是其中较为核心的代码,与整体逻辑还有差异,整体代码会在后面罗列。

1. 编写 UDP 版本的回显服务器

注:这里编写的客户端服务器是一个简单 UDP 版本的服务器,称之为:回显服务器。

一个普通的服务器: 收到请求,根据请求计算响应(业务逻辑),返回响应。

回显服务器: 省略了普通服务器的 “根据请求计算响应”,这里只是为了演示 socket api 的用法。

创建服务器前的初步准备

  1. 我们要知道,网络通信的本质就是操作网卡
  2. 但是网卡的直接操作十分不便,在操作系统内核中就使用了 socket 这样的文件来描述网卡。
  3. 因此要实现网络通信,就必须要先创建出一个 socket 对象

代码如下:

//这里定义成一个私有属性方便后续直接使用private DatagramSocket socket = null;

注:尤其对于一个服务器来讲,创建一个 socket 对象的同时,需要让其绑定一个明确的端口号。

因为在服务器在网络传输中处于一个被动的状态,没有一个明确的端口号,客户端就无法寻找到请求的服务器。

// 这里的 UdpEchoSever 是定义的服务器类名
// 这里的 port 就是一个服务器端口号public UdpEchoSever(int port) throws SocketException {socket = new DatagramSocket(port);}

形象的解释上面需要端口号的原因:
例如:
假设本人现在开了一家面馆,地址在地球村,美利坚1号,这里的 “1号” 就相当于端口号
假设本人的小面做的不错,口口相传我都在 “地球村,美利坚1号”。但是,如果我现在通过小推车贩卖小面,只是经常在 1号 门口售卖,有时到处跑,此时,客户就很难准确的找到我。
因此,固定的位置就很重要,端口也是如此!

创建服务器的核心原理以及代码

  1. 读取客户端发送过来的请求。

对于 UDP 来说,传输的基本单位是 DatagramPacket

这里要用 receive 方法来接受请求。
这里还需要再次说明一下关键字 receive
这个 receive 方法是一个 输出型参数,所以,这里需要先创建出来一个 空白的 DatagramPacket 对象,交给 receive 来填充(填充的是数据来自于网卡)

            //receive 方法是一个输出型参数,需要先创建好一个空白的 DatagramPacket 对象,交给 receive 方法来填充DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096 );socket.receive(requestPacket);

此时,接受过来的 DatagreamPacket 是一个特殊的对象,不方便处理,这里需要将其构造成一个字符串类型。

String request = new String(requestPacket.getData(),0, requestPacket.getLength());

解释上述字符串转换代码
如下:
我们已知,上面传递下来的元素是存储在数组中。 在这里插入图片描述
如上图所示,这里的数组不一定是用满的。因此,要构造字符串,构造的就是呢些使用的部分。 即就是调用 getLength()
方法获取实际长度。(0 ~ getLength() 范围的元素)

  1. 根据需求计算响应(这里写的是一个回显服务器,所以请求和响应相同)

获取处理后的元素

String response = process(request);

设计根据需求计算响应方法

	// 这里就是实现了一个回显public String process(String request){return request;}
  1. 将数据返回给客户端

这里将数据返回给客户端是 服务器 的工作。
因此,这里调用的 send 方法是属于 DatagramSocket 的,但是其发送的内容单元是 DatagramPacket 类型
发送回客户端前也就需要将 packet 构建好。

   DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());// 发送组织好的信息socket.send(responsePacket);

但是这里构造的相应对象与 接受时获取对象不同,这里构造的响应对象不可以使用空的字节数组,而是要使用响应的元素构造

  • 简单分析上述对象构造代码
    在这里插入图片描述
    要注意的是,这里获取字符的形式 第二种 最好,以字节的形式获取元素很少会出现元素缺失的情况,而字符相比于字节,单位就大了许多,自然风险也高。
  1. 打印一下处理元素时的中间情况
   System.out.printf("[%s:%d] req: %s; resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);

图示解释各个元素:
在这里插入图片描述

回显服务器整体代码罗列

整体展示 UDP 格式的服务器代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;//Udp版本的回显服务器
public class UdpEchoSever {//网络通信的本质是操作网卡//但是网卡的直接操作非常不方便,在操作系统内核中,就使用了 socket 这样的文件来描述网卡//因此要实现网络通信,就必须先创建出一个 socket 对象private DatagramSocket socket = null;//对于服务起来讲,创建 socket 对象同时,需要让其绑定上一个端口号//尤其针对服务器,更需要一个准确的端口号//因为服务器在网络传输中是处于被动的状态,没有明确地端口号,客户端就无法寻找到请求的服务器public UdpEchoSever(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("服务器启动");//要注意的是服务器不是给一个客户端服务的,需要服务很多的客户端while(true){//1. 读取客户端发送过来的请求//   使用 receive 方法接受请求。//receive 方法是一个输出型参数,需要先创建好一个空白的 DatagramPacket 对象,交给 receive 方法来填充DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096 );socket.receive(requestPacket);//此时 DatagramPacket 是一个特殊的对象,不方便处理,这里可以将数据拿出来,构造成一个字符串String request = new String(requestPacket.getData(),0, requestPacket.getLength());//2.根据请求计算响应,这里是一个回显服务器,所以请求和响应相同String response = process(request);//3.将响应数据返回给客户端// send 的参数也是 DatagramPacket 需要将这个 packet 构建好//      此处构造的响应对象,不可以使用空的字节数组,而是要用响应的元素构造DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);//4.打印一下,当前此次相应的中间处理结果System.out.printf("[%s:%d] req: %s; resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);}}//这个方法就是"根据需求计算响应"public String process(String request){return request;}public static void main(String[] args) throws IOException {//这里的端口可以随意设置UdpEchoSever sever = new UdpEchoSever(9090);sever.start();}
}

2. 编写 UDP 版本的回显客户端

对于客户端,我们要知道,就是来和对应的客户端进行通信的。
这里,我们就应该想起前面文章中提到的 网络通信的五元组
在这里插入图片描述
如上图所示,下面我们首先来实现基本设置。

回显客户端的基本设置

    private DatagramSocket socket = null;private String severIp = null;private int severPort = 0;//这里是构造方法public UdpEchoClient(String severIP,int severPort) throws SocketException {//这里不需要设定端口,让操作系统自动分配socket = new DatagramSocket();this.severIp = severIP;this.severPort = severPort;}
  • 首先这里构造的 socket 对象,不需要绑定一个固定的显示端口。随机挑选空闲的即可。

  • 其次,这里的
    源IP:127.0.0.1 已知。
    源端口:9090 前面已经设定。
    目的 IP:127.0.0.1 已知(环回IP)。
    目的端口:当前已经随机分配。 已知。

  • 最后使用的协议类型也已经明确。

到这里,基本上已经万事俱备,下面解释后面的操作。

编写客户端核心操作

  1. 从控制台获取要发送的数据

这里的操作比较简单直接展示代码:

        System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);//1. 从控制台读取要发送的数据//打印提示符System.out.println("> ");String request = scanner.next();if(request.equals("exit")){System.out.println("bye");break;}
  1. 构造成 UDP 请求并发送

这里要注意的是,此处要将信息发送出去,同样要调用 send 方法
前面说过,send 方法中传递的元素类型是 packet 类型。所以仍然需要构造 packet 类型,并且需要将 severIP 和 port 传入。

代码如下:

 //   上述 IP 地址是一个字符串,需要 InetAddress.getByName 来进行转换DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(severIp),severPort);socket.send(requestPacket);
  1. 读取服务器的 UDP 响应,并解析
    DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);socket.receive(responsePacket);String response = new String(responsePacket.getData(),0,requestPacket.getLength());

这里和前面服务器获取元素相同,同样使用 receive 方法将返回的信息填充。
最后转换成 String 类型。

  1. 将解析好的结果显示出来。
   System.out.println(response);

回显客户端整体代码罗列

整体展示 UDP 格式的客户端代码

import java.io.IOException;
import java.net.*;
import java.util.Scanner;//Udp版本的回显客户端
public class UdpEchoClient {private DatagramSocket socket = null;private String severIp = null;private int severPort = 0;//一次通信需要两个 IP 两个端口//客户端的 IP 是 127.0.0.1 已知//客户端的 端口号 是操作系统自动分配 已知//要进行传输,服务器的 IP 和 端口号 也需要传递给 客户端public UdpEchoClient(String severIP,int severPort) throws SocketException {//这里不需要设定端口,让操作系统自动分配socket = new DatagramSocket();this.severIp = severIP;this.severPort = severPort;}public void start() throws IOException {System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);//这里不只是一个客户端访问服务器while(true){//1. 从控制台读取要发送的数据//打印提示符System.out.println("> ");String request = scanner.next();if(request.equals("exit")){System.out.println("bye");break;}//2. 构造成 UDP 请求,并发送//   构造这个 Packet 的时候,需要将 severIP 和 port 传入。但是此处的 IP 需要的是一个 32 位的整数形式//   上述 IP 地址是一个字符串,需要 InetAddress.getByName 来进行转换DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(severIp),severPort);socket.send(requestPacket);//3. 读取服务器的 UDP 响应,并解析DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);socket.receive(responsePacket);// 将返回回来的信息构造为 String 字符串String response = new String(responsePacket.getData(),0,requestPacket.getLength());//4. 将解析好的结果显示出来System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);client.start();}
}

四、总结与代码运行结果解释

  1. 首先解释运行结果。
  • 启动客户端 / 服务器
    在这里插入图片描述
  • 运行示例
    在这里插入图片描述
    在这里插入图片描述
  1. 总结
    简单说明客户端和服务器之间的相互交流。
  • 说明服务器情况
    在这里插入图片描述

  • 说明客户端情况
    在这里插入图片描述

有关 UDP 的使用以及相关工作逻辑到此已经基本解释完毕,文笔浅薄,如有不足之处欢迎指出。

码子不易,您小小的点赞是对我最大的鼓励!!!

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

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

相关文章

100天精通Golang(基础入门篇)——第18天:深入解析Go语言中的结构体

🌷🍁 博主猫头虎 带您 Go to Golang Language.✨✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~&#x1…

半导体芯片介质膜层膜层膜厚测量仪

镀膜是半导体芯片制备过程中的重要步骤。在一个完整的CMOS工艺流程中,介质膜层(保护层、外延层、光刻胶和栅极氧化物等)与金属沉积层交替出现。随着芯片工艺节点不断进步,介质膜层也变得越来越复杂,在7nm工艺中,所需测量的介质膜堆…

AppStream下载元数据失败

错误:为仓库 AppStream 下载元数据失败 : Cannot prepare internal mirrorlist: No URLs in mirrorlist 目录 一、域名解析 二、CentOS-AppStream.repo 三、CentOS-Base.repo 四、CentOS-Extras.repo 五、rpm更新 一、域名解析 先验证 ping www.baidu.com 不…

STM32基于CubeIDE和HAL库 基础入门学习笔记:物联网项目开发流程和思路

文章目录: 第一部分:项目开始前的计划与准备 1.项目策划和开发规范 1.1 项目要求文档 1.2 技术实现文档 1.3 开发规范 2.创建项目工程与日志 第二部分:调通硬件电路与驱动程序 第三部分:编写最基础的应用程序 第四部分&…

基于dbn+svr的交通流量预测,dbn详细原理

目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) DBN+SVR的交通流量预测 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,是一种非常好的分类算法,本文将DBN+SVR用于交通流量预测…

怎样才能免费使用Qt开发闭源商业软件?

Qt 是一个跨平台的应用程序开发框架,其使用遵循 GNU Lesser General Public License(LGPL)开源许可协议。根据 LGPL 许可协议,您可以将 Qt 用于闭源商业软件,但是您需要满足以下条件: 1. 在您的软件中使用…

③ vue组件

vue组件创建 在App.vue中添加。 技巧:先import,把vue组件地址写出来。然后在template中写名字。剩下的就自动生成。要看下import有没有多生成什么。 注意1: 注意2: 不只是能在App.vue中引入组件。任意组件中都可以引用其他组件…

SRE之前端服务器的负载均衡

写在前面 今天和小伙伴们分享一些前端服务器的负载均衡技术内容为结合《 SRE Google运维解密》 整理: 涉及DNS 负载均衡VIP 负载均衡反向代理负载均衡 理解不足小伙伴帮忙指正 傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞…

Zabbix监控系统详解及配置

前言 作为一个运维,需要会使用监控系统查看服务器状态以及网站流量指标,利用监控系统的数据去了解上线发布的结果,和网站的健康状态。利用一个优秀的监控软件,我们可以: 通过一个友好的界面进行浏览整个网站所有的服务…

把大模型装进手机,分几步?

点击关注 文 | 姚 悦 编 | 王一粟 大模型“跑”进手机,AI的战火已经从“云端”烧至“移动终端”。 “进入AI时代,华为盘古大模型将会来助力鸿蒙生态。”8月4日,华为常务董事、终端BG CEO、智能汽车解决方案BU CEO 余承东介绍&#xff0c…

由于目标计算机积极拒绝,无法连接。 Could not connect to Redis at 127.0.0.1:6379

项目在启动时候报出redis连接异常 然后查看是redis 连接被计算机拒绝 解决方法 打开redis安装文件夹 先打开redis-servce.exe挂着,再打开redis-cli.exe 也不会弹出被拒接的问题了。而且此方法不用每次都去cmd里输入命令。

【黑马头条之app端文章搜索ES-MongoDB】

本笔记内容为黑马头条项目的app端文章搜索部分 目录 一、今日内容介绍 1、App端搜索-效果图 2、今日内容 二、搭建ElasticSearch环境 1、拉取镜像 2、创建容器 3、配置中文分词器 ik 4、使用postman测试 三、app端文章搜索 1、需求分析 2、思路分析 3、创建索引和…

C++多线程场景中的变量提前释放导致栈内存异常

多线程场景中的栈内存异常 在子线程中尝试使用当前函数的资源&#xff0c;是非常危险的&#xff0c;但是C支持这么做。因此C这么做可能会造成栈内存异常。 正常代码 #include <iostream> #include <thread> #include <windows.h>// 线程函数&#xff0c;用…

每日一题——对称的二叉树

题目 给定一棵二叉树&#xff0c;判断其是否是自身的镜像&#xff08;即&#xff1a;是否对称&#xff09; 例如&#xff1a; 下面这棵二叉树是对称的 下面这棵二叉树不对称。 数据范围&#xff1a;节点数满足 0≤n≤1000&#xff0c;节点上的值满足 ∣val∣≤1000 要求&…

Java课题笔记~ SpringMVC概述

1.1 SpringMVC简介 SpringMVC 也叫Spring web mvc。是Spring 框架的一部分&#xff0c;在Spring3.0 后发布的。 1.2 SpringMVC的优点 基于MVC 架构 基于 MVC 架构&#xff0c;功能分工明确。解耦合。 容易理解&#xff0c;上手快&#xff0c;使用简单 就可以开发一个注解…

服务器之LNMP

lnmp的构成 L&#xff1a;linux系统,操作系统。 N&#xff1a;nginx网站服务&#xff0c;前端,提供前端的静态页面服务。同时具有代理,转发的作用。 转发&#xff1a;主要是转发后端请求。转发到PHP。nginx没有处理动态资源的功能,他有可以支持转发动态请求的模块。 M&…

html实现商品图片放大镜,html图片放大镜预览

效果 实现 复制粘贴&#xff0c;修改图片路径即可使用 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>商品图片放大镜</title></head><style>body {margin: 0;padding: 0;}#app {padding: 10px;posit…

HTTP之cookie基础学习

目录 Cookie 什么是Cookie Cookie分类 Cookie版本 Cookie工作原理 Cookie详解 创建cookie cookie编码 cookie过期时间选项 Cookie流程 Cookie使用 会话管理 个性化信息 记录用户的行为 Cookie属性 domain选项 path选项 secure选项 cookie…

Stable Diffusion - 人物坐姿 (Sitting) 的提示词组合 与 LoRA 和 Embeddings 配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132201960 拍摄人物坐姿时&#xff0c;需要注意&#xff1a; 选择一个舒适和自然的坐姿&#xff0c;符合个性和心情。可以坐在椅子、沙发、长凳、…

通达OA SQL注入漏洞【CVE-2023-4165】

通达OA SQL注入漏洞【CVE-2023-4165】 一、产品简介二、漏洞概述三、影响范围四、复现环境POC小龙POC检测工具: 五、修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损…