【Java】面向UDP接口的网络编程

news2024/11/25 19:39:37

【Java】面向UDP接口的网络编程

  • 一. 基本通信模型
  • 二. API
    • DatagramSocket
    • DatagramPacket
  • 三. 回显服务器/客户端示例
    • 服务器
    • 客户端
    • 总结

一. 基本通信模型

在这里插入图片描述

  • UDP协议是面向数据报的,因此此处要构建数据报(Datagram)在进行发送。

二. API

DatagramSocket

DatagramSocket 是UDP Socket,⽤于发送和接收UDP数据报。
DatagramSocket 构造⽅法:

⽅法签名⽅法说明
DatagramSocket()创建⼀个UDP数据报套接字的Socket,绑定到本机任意⼀个随机端⼝(⼀般⽤于客⼾端)
DatagramSocket(int port)创建⼀个UDP数据报套接字的Socket,绑定到本机指定的端⼝(⼀般⽤于服务端)

DatagramSocket ⽅法:

⽅法签名⽅法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该⽅法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

DatagramPacket

DatagramPacket是UDP Socket发送和接收的数据报。
DatagramPacket 构造⽅法:

⽅法签名⽅法说明
DatagramPacket(byte[] buf, int length)构造 DatagramPacket用于接收长度为 length数据包。
DatagramPacket(byte[] buf,int length, SocketAddress address)构造数据报包,用于将长度为 length的数据包发送到指定主机上的指定端口号。address指定⽬的主机的IP和端⼝号
DatagramPacket​(byte[] buf, int length, InetAddress address, int port)构造一个数据报包,用于将长度为 length的数据包发送到指定主机上的指定端口号。

DatagramPacket ⽅法:

⽅法签名⽅法说明
InetAddress.getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端⼝号;或从发送的数据报中,获取接收端主机端⼝号
byte[] getData()获取数据报中的数据

三. 回显服务器/客户端示例

服务器

服务器端往往需要经历三个步骤:

  1. 读取客户端发来的请求并解析
//没有请求在receive处阻塞等待
 DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
 socket.receive(requestPacket);
 //读取到的字节数组转成String,方便后的逻续辑处理
 //getLength()得到的是有效长度
 String request=new String(requestPacket.getData(),0,requestPacket.getLength());

此处构造一个DatagramPacket用来接收请求,如果没有请求,则进入阻塞等待状态

  1. 根据请求计算响应
String response=process(request);

根据不同的业务场景,来设计不同的计算过程,可以将计算过程单独写一个方法:

//根据不同的需求,设计不同的计算处理
//此处只是将请求返回,来观察通信过程
public String process(String request) {
   return request;
}
  1. 把响应返回给客户端
//构造一个 DatagramPacket 作为响应对象
DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,
                                  requestPacket.getSocketAddress());
socket.send(responsePacket);
  1. [可选]打印日志
System.out.printf("[%s:%d] req:%s, rsep:%s\n",requestPacket.getAddress().toString(),
                  requestPacket.getPort(),request,response);

完整代码

import java.io.IOException;
import java.net.*;

public class UdpEchoServer {
    //socket为网卡
    private DatagramSocket socket=null;

    public UdpEchoServer(int port) throws SocketException {
        socket=new DatagramSocket(port);
    }
    //服务器启动逻辑
    public void start() throws IOException {
        System.out.println("server has been started!");
        while(true){
            //循环一次,请求一个请求-响应过程
            //1.读取请求并解析
            //没有请求在receive处阻塞等待
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //读取到的字节数组转成String,方便后的逻续辑处理
            //getLength()得到的是有效长度
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            //2.根据请求计算响应,此处只是简单的返回请求
            String response=process(request);
            //3.把响应返回给客户端
            //构造一个 DatagramPacket 作为响应对象
            DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),
                    response.getBytes().length,requestPacket.getSocketAddress());
            socket.send(responsePacket);

            //打印日志
            System.out.printf("[%s:%d] req:%s, rsep:%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(10100);
        server.start();
    }
}
  • 对于服务器端,往往会指定端口,便于客户端的访问。

客户端

客户端要从控制台读取客户的请求,因此需要经历四个步骤:

  1. 从控制台读取要发送的请求
Scanner scanner=new Scanner(System.in);
System.out.print(">");
//1.从控制台读取要发送的请求
if (!scanner.hasNext()) {
     break;
 }
String request=scanner.next();
  1. 构造数据报并发送
DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
                             InetAddress.getByName(serverIP),serverPort);
socket.send(requestPacket);

此处的serverIP和serverPort在构造方法处得到,这也是为什么我们要给服务器写一个指定的端口。

  1. 读取服务器的响应
DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
socket.receive(responsePacket);
  1. 把响应打印在控制台上
String response =new String(responsePacket.getData(),0,responsePacket.getLength());
System.out.println(response);

完整代码

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient{
    private DatagramSocket socket=null;
    private String serverIP;
    private int serverPort;

    public UdpEchoClient(String serverIP,int serverPort) throws SocketException {
        this.serverIP=serverIP;
        this.serverPort=serverPort;
        //客户端随机分配端口
        socket=new DatagramSocket();
    }
    public void start() throws IOException {
        System.out.println("client has been started!");
        Scanner scanner=new Scanner(System.in);
        while(true) {

            System.out.print(">");

            //1.从控制台读取要发送的请求
            if (!scanner.hasNext()) {
                break;
            }
            String request=scanner.next();
            //2.构造请求并发送
            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.把响应打印在控制台上
            String response =new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        //环回IP
        UdpEchoClient client=new UdpEchoClient("127.0.0.1",10100);
        client.start();
    }
}

  • 客户端是不需要指定端口的,是因为:指定的端口有可能被占用,且客户端往往由客户使用(不一定懂代码)。
  • "127.0.0.1"是回显地址,即本机地址。

总结

构造DatagramPacket的三种方法的使用场景:

⽅法签名⽅法说明
DatagramPacket(byte[] buf, int length)构造 DatagramPacket用于接收长度为 length数据包。
DatagramPacket(byte[] buf,int length, SocketAddress address)构造数据报包,用于将长度为 length的数据包发送到指定主机上的指定端口号。address指定⽬的主机的IP和端⼝号
DatagramPacket​(byte[] buf, int length, InetAddress address, int port)构造一个数据报包,用于将长度为 length的数据包发送到指定主机上的指定端口号。
  1. 第一种常用于服务器接收请求/客户端接收响应
  2. 第二种常用于服务器构造响应的数据报(由于接收了客户端的请求,可以读取到客户端的IP和端口号)
  3. 第三种常用于客户端构造请求的数据报(需要自行输入服务器的IP和端口号)

运行时,要先运行服务器,再运行客户端:
在这里插入图片描述

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

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

相关文章

Ubuntu 24.04 在 BPI-F3 上通过 SD 卡安装并从 NVME 运行

github 代码: https://github.com/rcman/BPI-F3 Ubuntu 24.04 现在正在我的 BPI-F3 上运行。很快会为 YouTube 制作一个视频。 这应该适用于任何版本的 Linux,仅在 Ubuntu 24.04 上测试过 入门 下载 Bianbu映像并使用您最喜欢的工具将其映像到微型 SD 卡…

进程 vs 线程:你需要知道的关键区别

“大树根深,才能迎风而立。” 进程:计算机中正在执行的程序的实例,它是操作系统进行资源分配的基本单位。 通过写特殊代码,把多个 CPU 核心都能利用起来,这样的代码就称为“并发编程”。 虽然多进程能够解决问题&…

PHP商会招商项目系统一站式服务助力企业腾飞

商会招商项目系统——一站式服务,助力企业腾飞 🚀💼 🚀 开篇:企业成长的加速器,商会招商项目系统来袭 在竞争激烈的市场环境中,企业如何快速找到适合自己的发展路径,实现腾飞&…

CUDA(C)磁态蒙特卡洛和传输矩阵多GPU并行计算分析

🎯要点 使用英伟达GPU、大都会和并行回火算法模拟蒙特卡洛。使用兰佐斯算法计算传输矩阵特征值。使用 Suzuki-Trotter 公式归一化量子无序系统。算法模型特征:多CUDA线程,多GPU和多任务式并行计算。 🍁磁态分析角度 Python和MA…

BUUCTF-[2019红帽杯]easyRE(Reverse逆向)

第一步 查壳 如图,无壳,ELF文件 第二步 IDA 64位IDA,无法直定位到主函数F5,所以使用,查找关键字符串定位主函数大法ShiftF12 发现这些关键字符串,双击上图蓝色字符串, 然后交叉引用CtrlX跟踪 …

硬件-示波器-巧用触发功能捕捉不连续的信号波形

文章目录 一:使用示波器的信号触发功能二:介绍示波器触发模式界面2.1 触发模式的AUTO档2.2 触发模式的Normal档(普通档)2.3 触发模式的single档(单次触发档) 三:在多通道的情况下,选…

电鳗带来灵感,防潮电源诞生,全打印技术的魅力

大家好!今天来了解一项受电鳗启发的防潮完全可打印电源的研究——《A moisture-enabled fully printable power source inspired by electric eels》发表于《PNAS》。随着可穿戴电子设备的发展,对安全、一次性且具成本效益的电源需求大增。传统电池存在不…

react native 与 react.js 的区别

React.js ReactJS是一个 JavaScript 库,支持前端 Web 和在服务器上运行,用于构建用户界面和 Web 应用程序。 它主要重点是Web 开发,遵循可重用组件的概念。 React 的虚拟 DOM 比传统的完全刷新模型更快,因为虚拟 DOM 只刷新页面的…

透过《当音乐停止之后》,理解2008年次贷危机:债务、流动性与资本的无声博弈

金融市场就像是整个经济体的循环系统,现代经济体依赖各种授信机制输送营养到整个系统,维持经济的正常运转。书中揭示了2008年次贷危机的背景,以及量化宽松(QE)政策的作用。通过作者的讲述,我们真正了解2008…

前端继承:原理、实现方式与应用场景

目录 一、定义 二、语法和实现方式 1.原型链继承 2.构造函数继承 3.组合继承 4.ES6类继承 三、使用方式 四、优点 五、缺点 六、适用场景 一、定义 前端继承是指在面向对象编程中,一个对象可以继承另一个对象的属性和方法。在前端领域,通常是指…

HC32F460KETA PETB JATA 工业 自动化 电机

HC32F460 系列是基于 ARM Cortex-M4 32-bit RISC CPU,最高工作频率 200MHz 的高性能 MCU。Cortex-M4 内核集成了浮点运算单元(FPU)和 DSP,实现单精度浮点算术运算,支持 所有 ARM 单精度数据处理指令和数据类型&#xf…

【精选】基于javaweb的流浪动物领养系统(源码+定制+开发)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

centos系列图形化 VNC server配置,及VNC viewer连接,2024年亲测有效

centos系列图形化 VNC server配置,及VNC viewer连接 0.VNC服务介绍 VNC英文全称为Virtual Network Computing,可以位操作系统提供图形接口连接方式,简单的来说就是一款桌面共享应用,类似于qq的远程连接。该服务是基于C/S模型的。…

鸿蒙NEXT开发-知乎评论小案例(基于最新api12稳定版)

注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下 如果大家觉得博主文章写的好的话,可以点下关注,博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…

vue实现列表自动滚动(纯与原生方式)

Vue实现列表自动滚动(纯与原生方式) 源码放在最后!1.效果展示: 2.功能说明: 该滚动可能存在的Bug: 1.如果你写的大屏不是使用的接口轮询的方式可能会存在也页面空白的情况(需要手动刷新才能触发列表滚动),因为我使用的是监听数据的变化然后…

软件供应链十年:探索开源的增长、风险和未来

回顾软件供应链状况报告的 10 年既是一个里程碑,也是一次行动号召。在过去十年中,开源消费改变了软件开发的世界。我们看到了前所未有的创新,但也出现了新的挑战,特别是在管理软件供应链的安全性和完整性方面。 在 Sonatype&…

基于SpringBoot民宿预订系统小程序【附源码】

效果如下: 管理员登录界面 管理员功能界面 用户管理界面 房东管理界面 小程序首页界面 民宿房间界面 功能界面 研究背景 随着旅游业的蓬勃发展和人们对旅行体验的不断追求,民宿作为一种独特的住宿方式,因其个性化、温馨及富含地方特色的服务…

disabled状态el-form下el-button的disabled的精细化控制

有一个很复杂的表单,支持编辑和查看两种模式。 查看时当然不希望编辑,最好是区分模式,在编辑模式下直接用div显示而不是用表单元素。这样工作量就有点大。那就考虑使用表单元素的disabled来让其不能编辑。如果每个表单元素都写这个玩意也是…

ssm职业高中学情成绩系统设计+jsp

系统包含:源码论文 所用技术:SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习,获取源码请私聊我 需要定制请私聊 目 录 摘 要 I Abstract II 第一章 绪论 1 1.1 研究背景 1 1.2 研究意义 1 1.3 研究内容 2 第二章 开发环…

codeforces round976 div2

A find minimum operations 思路&#xff1a;将所给的n变成k进制数&#xff0c;答案就是n的k进制形式下的位数之和 代码&#xff1a; #include <bits/stdc.h> using namespace std;typedef long long ll;ll n, k;void solve() {cin >> n >> k;ll cnt 0…