【JavaEE】_基于UDP实现网络通信

目录

1. 服务器

1.1 实现逻辑

1.2 代码

1.3 部分代码解释

2. 客户端

2.1 实现逻辑

2.2 代码

2.3 客户端部分代码解释

3. 程序运行结果

4. 服务器客户端交互逻辑


此篇内容为实现UDP版本的回显服务器echo server;

普通服务器:收到请求,根据请求计算响应,返回响应;

回显服务器:忽略计算,直接将收到的请求作为响应返回;

如需实现其他功能,修改响应计算方法process内容即可);

具体实现代码如下:

1. 服务器

1.1 实现逻辑

对于网络通信的服务器需要进行的工作为:

1. 读取请求并解析;

2. 根据请求计算响应;

3. 把响应写回客户端;

4. 打印交互详细信息;

1.2 代码

package TestDemo1;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UDPEchoServer {// 创建一个DatagramSocket对象,作为后续操作网卡的基础private DatagramSocket socket = null;public UDPEchoServer(int port) throws SocketException{// 显式指定服务器端口号socket = new DatagramSocket(port);}public void start() throws IOException {// 服务器启动方法System.out.println("服务器启动");// 为保证服务器随时向客户端提供服务while(true){// 1. 读取请求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);// DatagramPacket对象用于承载从网卡读到的数据,收到数据时需要创建一个内存空间保存这个数据,// DatagramPacket内部不能自行分配内存空间,需要程序员手动创建socket.receive(requestPacket);// 完成receive之后,数据以二进制形式存储在DatagramPacket中// 需要将二进制数据转成字符串String request = new String(requestPacket.getData(),0, requestPacket.getLength());// 取0~requestPacket.getLength()区间内的字节构成一个String对象;//2. 根据请求计算响应String response = process(request);//3. 把响应写回客户端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 {UDPEchoServer server = new UDPEchoServer(9090);// 可以在1024~65535(临时端口)中任意选取端口号server.start();}
}

1.3 部分代码解释

1. 为方便计算请求,将请求的DatagramPacket对象构造成字符串时只需获取DatagramPacket对象中实际有效的部分数据,requestPacket.getLength()获取到的就是收到数据的真实长度而非4096这个最大长度:

2. 已经了解过UDP本身是无连接的,故而对于每一次通信过程,在构造数据报时都需要指定数据报要发给谁;

(1)对于构造的responsePacket对象有3个参数:

DatagramPacket responsePacket = new DatagramPacket(                   
response.getBytes(),
response.getBytes().length,
requestPacket.getSocketAddress());

response.length()获取到的是响应对象字符串的字符个数,

response.getBytes().length获取到的是响应对象字符串的字节个数;

requestPacket.getSocketAddress()获取到的是请求发送方(即客户端)的IP与端口号

(2)注意response.getBytes.length(字节个数)与response.getlength()(字符个数)的区别:

如果response字符串都是英文字符则二者相等,如果包含中文则二者不同;

在进行网络传输时,必然是需要通过字节为单位进行通信的。

3. while(true)会使程序处于快速循环的状态,每循环一次就处理一次请求响应,

当客户端发出请求时,recerive就能顺利读取请求,客户端没有发出请求时,receive就会阻塞

如果客户端发出的请求过多,可以使用多线程冲动调动计算机硬件资源,也可以再多开机器,但多开机器又会涉及到分布式问题;

4. 使用格式化输出Packet的IP与端口号:

5. 前文已经提及socket也是一个文件,但在上文代码中并未进行close操作,却没有造成文件资源泄漏的原因是:

socket是文件描述符表中的一个表项,每次打开一个文件就会占用一个位置,文件描述符在pcb上,是跟随进程的。在上文代码中创建的socket对象在整个程序运行过程中都需要使用,不可以提前关闭,当socket不需要使用时,即代表程序结束了,进程结束了,文件描述符表也销毁了,伴随着销毁都被系统自动回收了。故而不会造成文件资源泄露问题

只有代码中频繁打开文件但不关闭,在一个进程的运行过程中,不断积累打开的文件,逐渐消耗掉文件描述符表中的内容,最后消耗殆尽,才会造成泄露。

对于生命周期很短的进程,无需考虑泄露,在客户端方一般来说影响不大。

2. 客户端

2.1 实现逻辑

对于网络通信的客户端,需要进行的工作是:

1. 从控制台读取数据作为客户端发出的请求;

2. 将请求字符串request构造成请求requestPacket对象,发送给服务器;

3. 尝试读取服务器返回的响应;

4. 将响应responsePacket对象构造成响应response字符串,显示出来;

2.2 代码

package TestDemo1;import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UDPEchoClient {private DatagramSocket socket = null;private String serverIp = "";private int serverPort = 0;public UDPEchoClient(String ip, int port) throws SocketException {// 客户端的socket对象需令系统自动分配socket = new DatagramSocket();// UDP本身不持有对端信息,需要在应用程序中记录对端信息(IP与端口)serverIp = ip;serverPort = port;}public void start() throws IOException {// 客户端启动方法System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);while(true){// 1. 从控制台读取数据作为客户端发出的请求System.out.println("->");String request = scanner.next();// 2. 将请求字符串request构造成请求requestPacket对象,发送给服务器DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIp), serverPort);socket.send(requestPacket);// 3. 尝试读取服务器返回的响应DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);// 4. 将响应responsePacket对象转换为响应字符串response,显示出来String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UDPEchoClient client = new UDPEchoClient("127.0.0.1", 9090);client.start();}
}

2.3 客户端部分代码解释

1.DatagramPacket的三个构造方法

第一种:只指定字节数组缓冲区,用于服务器接收请求与客户端接收响应时使用

第二种:指定字节数组缓冲区与InetAddress对象(同时包含IP与端口),用于服务器向客户端发回响应时使用

第三种:指定字节数组缓冲区,同时指定IP与端口号

2. 客户端对服务器发出请求的过程:

对于服务器端口必须是确定的:程序员可以手动分配空闲端口给当前服务器使用即可,

代码为:

socket = new DatagramSocket(port);

客户端一般都采取系统分配的方式:也可以指定端口,但不推荐。一方面,因为指定的端口可能被其他进程占用,如果被占用就会产生端口号冲突,运行就会抛出异常,提示绑定端口失败;另一方面,如果客户端出现了端口冲突,让客户手动解决也是不现实的。

代码为:

socket = new Datagramocket();

3. 端口与进程的关系:

端口号用于标识或区分一个进程,因此在同一台主机上,不允许一个端口同时被多个进程使用;

但是一个进程可以绑定多个端口;

socket和端口是一一对应的,进程与socket是一对多的

3. 程序运行结果

首先启动EchoServer,再启动EchoClient,在客户端输入请求字符串后查看运行结果:

客户端与服务器通信成功。

4. 服务器客户端交互逻辑

1. 服务器先启动,启动后进入循环,执行到receive处阻塞;

2. 客户端开始启动后,进入循环执行scanner.next(),在此处阻塞。

    当客户在控制台输入内容后,next返回作为请求,继而构造请求数据并发送给服务器;

3. 客户端发送数据后,

服务器从receive中返回,解析请求构造字符串,执行process操作计算响应,构造响应后执行send发回给客户端;

客户端执行到receive处等待服务器的响应;

4. 客户端获取到从服务器返回的数据后,从receive中返回,继而显示响应内容;

5. 服务器完成一次循环后又执行到receive处,客户端完成依次循环后又执行到scanner.next处,二者均进入阻塞状态;

注意:当服务器程序在普通私有ip计算机上运行时,若不在一个局域网中,无法实现跨主机访问。

如果服务器程序在特殊的计算机:云服务器上,就拥有了公有ip,可以实现跨主机访问。

此部分内容后续详解。

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

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

相关文章

Docker搭建MySQL主从数据库-亲测有效

1、测试环境概述 1、使用MySQL5.7.35版本 2、使用Centos7操作系统 3、使用Docker20版本 案例中描述了整个测试的详细过程 2、安装Docker 2.1、如果已经安装docker,可以先卸载 yum remove -y docker \ docker-client \ docker-client-latest \ docker-common \ docker-l…

机器人电机综述 — 电机分类、舵机、步进与伺服、物理性质和伺服控制系统

电机综述 图片与部分素材来自知乎大佬不看后悔!最全的电机分类,看这一篇就够了! - 知乎 (zhihu.com),本文只是把机器人中常用的电机知识提炼了一下 1 按照结构和工作原理划分 1. 同步电机 ​ 电机的转速与定子磁场的转速相同步…

线性表的案例引入 | 稀疏多项式的运算

#include <iostream> using namespace std;#define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2typedef int Status;// 定义单链表 typedef struct PNode {float coef; //系数int expn; //指数struct PNode *nex…

基于深度学习的细胞感染性识别与判定

基于深度学习的细胞感染性识别与判定 基于深度学习的细胞感染性识别与判定引言项目背景项目意义项目实施数据采集与预处理模型选择与训练模型评估与优化 结果与展望结论 基于深度学习的细胞感染性识别与判定 引言 随着深度学习技术的不断发展&#xff0c;其在医学图像处理领域…

【UEFI基础】EDK网络框架(UDP4)

UDP4 UDP4协议说明 UDP的全称是User Datagram Protocol&#xff0c;它不提供复杂的控制机制&#xff0c;仅利用IP提供面向无连接的通信服务。它将上层应用程序发来的数据在收到的那一刻&#xff0c;立即按照原样发送到网络。 UDP报文格式&#xff1a; 各个参数说明如下&…

基础+常用的数据结构

基础 java基础 JDK 和 JRE JDK&#xff0c;它是功能齐全的 Java SDK&#xff0c;是提供给开发者使用&#xff0c;能够创建和编译 Java 程序的开发套件。它包含了 JRE,同时还包含了编译 java 源码的编译器 javac 以及一些其他工具比如 javadoc&#xff08;文档注释工具&#…

舵机使用总结

文章目录 1 舵机简介2 注意事项3 编写驱动程序3.1 使用STM32作为控制器3.1.1 计算高电平对应程序中的取值范围3.1.2 编写控制程序 1 舵机简介 舵机使用PWM控制&#xff0c;周期为20ms&#xff0c;通过改变高电平占空比来驱动&#xff0c;高电平通常为1~2ms&#xff08; 或 0.5 …

Find My卡片正成为消费电子香饽饽,伦茨科技ST17H6x可以帮到您

今年CES许多公司发布支持苹果Find My的卡片产品&#xff0c;这种产品轻薄可充电&#xff0c;放在钱包、背包或者手提包可以防丢查找&#xff0c;在智能化加持下&#xff0c;防丢卡片使得人们日益关心自行车的去向。最新的防丢卡片与苹果Find My结合&#xff0c;智能防丢&#x…

vue生命周期图示

详见&#xff1a;官网介绍

聊聊Java虚拟机(一)—— 类加载子系统

1. 前言 ​ 虚拟机就是一款用来执行虚拟计算机指令的计算机软件。它相当于一台虚拟计算机。大体上&#xff0c;虚拟机分为系统虚拟机和程序虚拟机。系统虚拟机就相当于一台物理电脑&#xff0c;里面可以安装操作系统&#xff1b;程序虚拟机是为了执行单个计算机程序而设计出来…

海外媒体发稿:出口贸易媒体发稿推广8种方式让您事半功倍-华媒舍

出口贸易已成为越来越多企业的发展方向。要让更多潜在客户了解并选择你的产品&#xff0c;仅靠传统的销售手段已远远不够。作为一名出口贸易从业人员&#xff0c;如何利用媒体发稿推广&#xff0c;事半功倍地扩大市场影响&#xff0c;成为摆在我们面前的一大任务。本文将为您介…

Vulnhub-TECH_SUPP0RT: 1渗透

文章目录 一、前言1、靶机ip配置2、渗透目标3、渗透概括 开始实战一、信息获取二、使用smb服务获取信息三、密码破解四、获取webshell五、反弹shell六、web配置文件获取信息七、提权 一、前言 由于在做靶机的时候&#xff0c;涉及到的渗透思路是非常的广泛&#xff0c;所以在写…

【c++】C++输入输出

C输入&输出 新生婴儿会以自己独特的方式向这个崭新的世界打招呼&#xff0c;C刚出来后&#xff0c;也算是一个新事物&#xff0c;那C是否也应该向这个美好的世界来声问候呢&#xff1f;我们来看下C是如何来实现问候的 #include<iostream> // std是C标准库的命名空间名…

全网最高质量文章:重新学习Java中的HashMap!!

前言 本文参考了美团技术团队的科普文章Java 8系列之重新认识HashMap - 知乎 (zhihu.com) 这篇文章的质量极其高&#xff0c;高到很有可能是全网介绍HashMap这个知识点最优秀的文章&#xff0c;没有之一&#xff01;&#xff01;&#xff01;因此&#xff0c;我决定在我自己的…

idea消除代码区黄色警告

文章目录 前言一、修改配置总结 前言 idea的检查项较多&#xff0c;导致警告比较多看上去很不雅观。 一、修改配置 在idea中打开Settings 取消Warning和Weak Warning的勾选 总结 回到顶部

多线程-线程状态和线程安全(加锁-synchronized 关键字)

目录 1.线程状态 示例&#xff1a; 1.1线程状态和状态转移的意义 2.线程安全 2.1观察线程不安全 2.2线程不安全的原因 3.synchronized 关键字 - 监视器锁 monitor lock 3.1synchronized 的特性 1. 互斥 2.可重⼊ 应用示例&#xff1a; 3.2synchronized 使⽤⽰例 1.…

conda国内加速

1、配置国内源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ 2、显示源地址 conda config --set show_channel_urls yes

【Arduino】基于 I2C 模块通过 I2C 接口驱动 LCD1602 字符液晶显示模块显示文本:只需两个引脚即可控制 LCD1602 液晶屏

引言 LCD1602是一种16列2行的字符液晶显示模块&#xff0c;常用于Arduino等嵌入式系统的用户接口。为了简化连接和编程&#xff0c;我们将使用I2C接口&#xff0c;这只需要Arduino的两个模拟输入引脚。 步骤 安装 LiquidCrystal_I2C 库 为了在Arduino中使用I2C模块驱动LCD显…

Linux的Shell程序(全面超详细的介绍)

文章目录 前言1.Shell概述1.1概述 2.Shell解析器3.Shell脚本入门4.Shell中的变量4.1 系统变量4.2 自定义变量4.3 特殊变量&#xff1a;$n4.4 特殊变量&#xff1a;$#4.5 特殊变量&#xff1a;\$*、$4.6 特殊变量&#xff1a;$&#xff1f; 5.运算符6.条件判断7.流程控制7.1 if …

Hive-SQL语法大全

Hive SQL 语法大全 基于语法描述说明 CREATE DATABASE [IF NOT EXISTS] db_name [LOCATION] path; SELECT expr, ... FROM tbl ORDER BY col_name [ASC | DESC] (A | B | C)如上语法&#xff0c;在语法描述中出现&#xff1a; []&#xff0c;表示可选&#xff0c;如上[LOCATI…