JavaEE 编写Java程序,实现一个简单的echo程序(网络编程UDP实践练习)

UDP Client 和 UDP Server 的实现分析与解读

UDP(User Datagram Protocol,用户数据报协议)是一种无连接的网络协议,相比于TCP,它不保证数据包的可靠送达和顺序。因此,UDP在网络应用中,尤其是对实时性要求较高、容错能力强的应用场景中,得到了广泛的应用。本文将结合 UdpClientUdpServer 这两个示例程序,分析它们的实现及相关的注释内容,帮助大家更好地理解UDP的使用。

1. UDP Client(客户端)
代码分析
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;/*** Description://UDP的特点是无连接* 就是通信双方,不保存对方的信息(IP+端口号)* DatagramSocket和DatagramPacket是UDP中的两个重点api* Date: 2025-02-20* Time: 21:48*/public class UdpServer {private DatagramSocket socket = null;public UdpServer(int port) throws SocketException {//对于服务器这来说, 需要在socket对象创建的时候就制定一个端口号,作为构造方法的参数//后续服务器开始运行的时候,操作系统就会把端口号和进程关系起来//在调用这个构造方法的过程中,jvm就会调用系统中的socket api,完成端口号-进程的关联//也就是"绑定端口号"//对于一个系统来说,同一时刻,一个端口号,只能绑定一个进程//但是一个进程可以绑定多个端口号,类似手机号一个人有多个//如果有多个进程,先绑定之后,后来的想要绑定的进程就会失效socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("UDP 服务器 Started");//对于服务器来说,主要的工作就是时刻准备好处理客户端传来的请求//所以这里要通过一个死循环,不停的处理来自客户端的请求while (true) {//接下来就是服务器开发三板斧//1. 读取客户端的请求并且解析//receive 是从网卡上获取数据//但是调用receive的时候网卡上不一定有数据,如果没有收到数据,// receive就会一直阻塞,直到等待真正收到数据为止//和inputStream.read(buffer)一样receive也是通过输出型参数获取到网卡上收到数据的//receive 的参数是DatagramPacket//dataframerequestPacket 的自身需要存储数据,但是存储数据有多大,需要外部指定:DatagramPacket requestPacket = new DatagramPacket(new byte[1024], 1024);socket.receive(requestPacket);//上述收到的数据,是二进制byte[] 的形式体现的,后续代码如果要进行打印之类的处理操作//需要转化成字符串才好处理//这个方法是用来构造String对象//问题为什么要用getData()String request = new String(requestPacket.getData(), 0, requestPacket.getLength());//2. 根据请求计算响应//此处请求就是响应,所以String response = process(request);//3. 把响应写回到客户端//此处response.getBytes().length 获取的是字节数组的长度//而不是response.length,这个方法获得的是字符串中字符的个数//如果输入的是中文,字符个数不等于字节的个数,比如,utf-8一个中文对应3个字节//因为UDP无连接,所以在send的时候就需要在send的数据包中把要对端的信息写进去,这样才能把信息返回//所以要用两个方法分别返回address和portDatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length, requestPacket.getAddress(), requestPacket.getPort());socket.send(responsePacket);//把日志打印System.out.printf("[%s:%d] req = %s , resp %s\n", requestPacket.getAddress(),requestPacket.getPort(),request,response);}}private String process(String request) {request = request.replace(" ", "");return request;}public static void main(String[] args) throws IOException {UdpServer server = new UdpServer(9090);server.start();}
}
代码和思想分析
  1. Socket的创建:客户端在创建DatagramSocket时,不指定端口号。因为客户端是主动发送数据的一方,它只需要通过一个临时的端口与服务器通信。若指定端口号,可能会发生端口冲突(即目标端口已被其他进程占用)。这是UDP协议的特性之一,避免了不必要的冲突。

  2. 构造DatagramPacket:客户端构造了一个DatagramPacket对象,里面封装了待发送的数据(来自控制台输入),以及目标IP地址和端口号。InetAddress.getByName(serverIP)将目标服务器的IP地址转换为InetAddress类型。

  3. 发送数据包:通过socket.send(requestPacket)方法将数据包发送给服务器。由于UDP是无连接的协议,发送数据时不需要建立正式的连接。

  4. 接收数据包:客户端通过socket.receive(responsePacket)接收服务器的响应,接收到的数据为字节数组,之后将其转换为字符串并打印。

  5. 循环操作:客户端的工作是持续不断地从用户获取输入,发送数据,并接收服务器响应,直到用户退出程序。

2. UDP Server(服务器端)
代码分析
import java.io.IOException;
import java.net.*;
import java.util.Scanner;/*** Description:* Date: 2025-02-20* Time: 21:49*/
public class UdpClient {DatagramSocket socket = null;private String serverIP;private int serverPort;//客户端这一边创建socket不要制定端口号,客户端是主动的一方//不需要服务器来找他,而且如果制定了a端口号,如果服务器的a端口此时正在执行其他进程,这样就会产生冲突public UdpClient(String serverIP,int serverPort) throws SocketException {socket = new DatagramSocket();this.serverIP = serverIP;this.serverPort = serverPort;}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. 构造出一个UDP请求,发送给服务器//此处是给服务器发送数据,发送数据的时候,UDP数据报里面就需要有带有目标的IP和端口//接受数据的时候,构造的UDP数据报,就是一个空的数据报//此处要使用InetAdress来包裹IP,因为这里的serverIP是二进制的格式,// 但是这个DatagramPacket构造方法只接受整数类型的IP地址,所以要包裹DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(this.serverIP),this.serverPort);//发送给服务器socket.send(requestPacket);//3. 从服务器读取到响应DatagramPacket responsePacket = new DatagramPacket(new byte[1024], 1024);socket.receive(responsePacket);//4. 把响应打印String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UdpClient udpClient = new UdpClient("127.0.0.1",9090);udpClient.start();}}
代码和思想分析
  1. Socket的创建与端口绑定:与客户端不同,服务器在创建DatagramSocket时需要指定端口号。这个端口号与服务器进程绑定,操作系统会将该端口与服务器进程关联。若同一端口已被其他进程占用,新的进程将无法绑定该端口。

  2. 接收数据:服务器通过socket.receive(requestPacket)接收客户端发送的UDP数据包。receive()方法是阻塞的,直到数据包到达。数据包的内容是二进制数据,接收后将其转换为字符串进行处理。

  3. 处理请求:服务器通过process()方法处理客户端的请求。在这个示例中,处理逻辑非常简单——去除字符串中的空格。实际应用中,服务器可能会根据不同的业务需求对请求进行更加复杂的处理。

  4. 响应客户端:服务器处理完请求后,通过DatagramPacket将响应数据返回给客户端。发送的数据包需要包含客户端的地址和端口号,UDP协议依赖这些信息来正确地将数据返回给请求方。

  5. 打印日志:每次接收请求并发送响应后,服务器都会打印日志,显示请求的来源地址、端口,以及请求和响应的内容。

3. 总结与思考

通过这两个示例,我们可以更好地理解UDP协议的工作方式:

  • 无连接特性:UDP不需要像TCP那样建立连接,客户端和服务器通过DatagramSocketDatagramPacket直接发送和接收数据。它是无连接的,这使得它在实时通信和网络游戏等场景中非常有用。

  • 高效性:由于没有连接的建立和拆除过程,UDP的通信速度通常比TCP更快,适用于对时延敏感的应用。然而,UDP不保证数据的可靠性,发送的数据包可能会丢失或乱序。

  • 数据报格式:UDP使用数据报(Datagram)进行通信,每个数据包都包含目标IP和端口信息。客户端发送数据时,数据包需要包含目标服务器的IP和端口;服务器响应数据时,数据包需要包含客户端的IP和端口。

  • API的使用DatagramSocketDatagramPacket是UDP通信的核心API,前者用于发送和接收数据,后者用于封装数据及其目的地址。

4. 代码中的关键语法和思想
  • 客户端不指定端口:客户端在创建DatagramSocket时不指定端口号,这是因为它是主动发送数据的一方。若指定端口,可能会导致端口冲突。

  • 阻塞式接收:服务器端使用socket.receive()接收数据包,这个方法会阻塞直到接收到数据包,因此可以通过死循环处理不断到来的客户端请求。

  • 字节数组与字符串的转换:在处理UDP数据时,收到的都是字节数据,使用getData()获取字节数组,再根据需要将其转换为字符串。特别注意getLength()方法,它返回的是有效数据的长度,不是字节数组的总长度。

以上就是UDP客户端和服务器端代码的整体分析和注释解读。通过这些示例,我们可以清晰地看到UDP协议的基本使用方法,以及其在不同场景中的应用。

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

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

相关文章

【2025全网最新最全】前端Vue3框架的搭建及工程目录详解

文章目录 安装软件Node.js搭建Vue工程创建Vue工程精简Vue项目文件 Vue工程目录的解读网页标题的设置设置全局样式路由配置 安装软件Node.js 下载地址:https://nodejs.org/zh-cn/ 安装完成后,打开cmd,查看环境是否准备好 node -v npm -vnpm使用之前一定…

Java 之集成 DataX 数据同步工具

1、官网下载 DataX https://github.com/alibaba/DataX 2、将依赖添加到本地(DataX没有maven坐标,需要自己安装) mvn install:install-file -Dfile"datax-common-0.0.1.jar" "-DgroupIdcom.datax" "-DartifactIdda…

OpenEuler学习笔记(三十五):搭建代码托管服务器

以下是主流的代码托管软件分类及推荐,涵盖自托管和云端方案,您可根据团队规模、功能需求及资源情况选择: 一、自托管代码托管平台(可私有部署) 1. GitLab 简介: 功能全面的 DevOps 平台,支持代码托管、C…

pikachu

暴力破解 基于表单的暴力破解 【2024版】最新BurpSuit的使用教程(非常详细)零基础入门到精通,看一篇就够了!让你挖洞事半功倍!_burpsuite使用教程-CSDN博客 登录页面,随意输入抓包,发送到攻击…

Springboot基础篇(3):Bean管理

前言:Spring 通过扫描类路径(Classpath)来查找带有特定注解(如 Component、Service、Repository 等)的类,并将它们注册为 Spring 容器中的 Bean。 1 Bean扫描 Bean 扫描是 Spring 框架的核心功能之一&…

VidSketch:具有扩散控制的手绘草图驱动视频生成

浙大提出的VidSketch是第一个能够仅通过任意数量的手绘草图和简单的文本提示来生成高质量视频动画的应用程序。该方法训练是在单个 RTX4090 GPU 上进行的,针对每个动作类别使用一个小型、高质量的数据集。VidSketch方法使所有用户都能使用简洁的文本提示和直观的手绘…

Vulhub靶机 Apache APISIX Dashboard RCE(CVE-2021-45232)(渗透测试详解)

一、开启vulhub环境 docker-compose up -d 启动docker ps 查看开放的端口 影响范围 2.7 ≤ Apache APISIX Dashboard < 2.10.1 二、访问靶机IP 9080端口 1、下载利用脚本&#xff0c;并利用 https://github.com/wuppp/apisix_dashboard_rce 这里需要注意IP的端口为9000…

Python - Python连接数据库

Python的标准数据库接口为&#xff1a;Python DB-API&#xff0c;Python DB-API为开发人员提供了数据库应用编程接口。 PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个实现库&#xff0c;Python2中则使用mysqldb。 PyMySQL 遵循 Python 数据库 API v2.0 规范&…

Windows 11【1001问】Windows 11 都有哪些版本?

随着Windows 11的普及&#xff0c;越来越多的用户开始关注其不同版本及其分支版本之间的差异。在此之前&#xff0c;我们已经通过一系列文章详细介绍了Windows 11的基本概念、硬件配置要求、系统镜像下载方法以及多种安装方式。从使用Rufus和UltraISO软碟通制作Windows 11系统安…

【Kimi】自动生成PPT-并支持下载和在线编辑--全部免费

【Kimi】免费生成PPT并免费下载 用了好几个大模型&#xff0c;有些能生成PPT内容&#xff1b; 有些能生成PPT&#xff0c;但下载需要付费&#xff1b; 目前只有Kimi生成的PPT&#xff0c;能选择模板、能在线编辑、能下载&#xff0c;关键全部免费&#xff01; 一、用kimi生成PP…

【Java项目】基于Spring Boot的旅游管理系统

【Java项目】基于Spring Boot的旅游管理系统 技术简介&#xff1a;采用Java技术、Spring Boot框架、MySQL数据库等实现。 系统简介&#xff1a;旅游管理系统是一个基于Web的在线平台&#xff0c;主要分为前台和后台两大功能模块。前台功能模块包括&#xff08;1&#xff09;首…

Deepseek开源周第三天:DeepGEMM发布

Deepseek开源周第三天&#xff1a;DeepGEMM发布 前言 上周deepseek宣布&#xff0c;将在本周陆续发布五个开源项目&#xff0c;这些库已经在生产环境中经过了记录、部署和实战测试。 今天是deepseek开源周的第三天&#xff0c;deepseek发布了一个名为 DeepGEMM 的项目&#x…

ALM研发管理:全新甘特图,让项目管理更高效

在软件开发领域&#xff0c;甘特图一直是项目管理的重要工具。通过可视化的任务时间线&#xff0c;清晰地展示项目的进度和关键时间节点&#xff0c;帮助团队成员快速理解项目状态&#xff0c;协调工作进度&#xff0c;从而有效提升项目管理的效率。无论是需求分析、设计、开发…

mac os 使用 root 登录

打开系统偏好设置。进入“用户与群组”面板。点按锁按钮输入密码&#xff0c;再点最下面的登录选项。在右边面板的下方你会看见一行字&#xff1a;”网络账户服务器&#xff1a;加入 ”&#xff0c;点击加入&#xff0c;就可以打开目录实用工具了。 添加Root用户 正常情况下目…

【C++笔记】C++11智能指针的使用及其原理

【C笔记】C11智能指针的使用及其原理 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】C11智能指针的使用及其原理前言1.智能指针的使用场景分析2. RAII和智能指针的设计思路3. C标准库智能指针的使用4. 智能指针的原…

SQL命令详解之操作数据库

操作数据库 SQL是用于管理和操作关系型数据库的标准语言。数据库操作是SQL的核心功能之一&#xff0c;主要用于创建、修改和删除数据库对象&#xff0c;如数据库、表、视图和索引等。以下是SQL中常见的数据库操作命令及其功能简介&#xff1a; 1. 查询数据库 查询所有的数据库…

轨迹控制--odrive的位置控制---负载设置

轨迹控制 此模式使您可以平滑地使电机旋转&#xff0c;从一个位置加速&#xff0c;匀速和减速到另一位置。 使用位置控制时&#xff0c;控制器只是试图尽可能快地到达设定点。 使用轨迹控制模式可以使您更灵活地调整反馈增益&#xff0c;以消除干扰&#xff0c;同时保持平稳的运…

mysql.gtid_executed表、gtid_executed变量、gtid_purged变量的修改时机

1.2 mysql.gtid_executed表、gtid_executed变量、gtid_purged变量的修改时机 1.2.1 定义 mysql.gtid_executed表&#xff1a;GTID持久化的介质&#xff0c;GTID模块初始化的时候会读取这个表作为获取gtid_executed变量的基础。 gtid_executed变量&#xff1a;表示数据库中执行…

CONTACT 在 Ubuntu 系统中的安装与使用

CONTACT 概述 CONTACT 是研究三维摩擦接触问题的高级仿真程序&#xff0c;如轮轨之间、滚动轴承的接触问题。CONTACT 提供了完整且详细的解决方案&#xff0c;可集成到多体仿真软件中。其计算质量可与有限元分析相近&#xff0c;但计算时间仅为后者的千分之一。CONTACT 采用半…

C#连接sql server

连接时&#xff0c;出现如下提示&#xff1a; ERROR [IM014] [Microsoft][ODBC 驱动程序管理器] 在指定的 DSN 中&#xff0c;驱动程序和应用程序之间的体系结构不匹配 原因是odbc的驱动和应用程序的架构不一致。我的odbc如下所示&#xff1a; 显示为64位&#xff0c;而c#程序显…