【Java网络编程】基于UDP-Socket 实现客户端、服务器通信

news2024/9/23 9:33:07

哈喽,大家好~我是你们的老朋友:保护小周ღ  


本期为大家带来的是网络编程的 UDP Socket 套接字,基于 UDP协议的 Socket 实现客户端服务器通信,Socket 套接字可以理解为是,传输层给应用层提供的一组 API,如此程序,确定不来看看嘛~~


本期收录于博主的专栏JavaEE_保护小周ღ的博客-CSDN博客

适用于编程初学者,感兴趣的朋友们可以订阅,查看其它 “JavaEE基础知识”。
更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* ‘


Socket 套接字可以理解为是操作系统提供给程序员的一组用于网络编程的API (接口)——传输层的接口,传输层给应用层提供的一组 API,统称为 Socket API 。网络通信的底层逻辑都已经被操作系统封装好了,开发人员就可以根据接口开发实现网络通信。

Socket 套接字主要针对传输层协议分为如下三类:

  • 字节流套接字:使用传输层TCP协议
  • 数据报套接字:使用传输层UDP协议
  • 原始套接字:用于自定义传输层协议

 本篇博客主要讲述面向数据报的网络编程。


一、Java基于UDP数据报套接字通信模型

UDP 协议的特点:

  1. 面向无连接:传输数据之前,通信双方不依赖于建立连接,只需要知道谁发给谁即可。
  2. 不可靠传输:只负责发送,不关注数据是否传输成功,即使没发送成功啥也不干,也没有反馈
  3. 面向数据报:使用 UDP 数据报的形式传输,数据报可以理解为数据是一块一块的传输。
  4. 有缓存区的概念:接收缓冲区,发送缓冲区:在进行网络数据通信时,用于存储待发送或已接收数据的缓冲区。
  5. 数据传输大小受限制:一个UDP 数据报最大占 64k, 1k = 1024字节
  6. 全双工通信:通信双方都可以同时进行信息交互

总结:UDP 协议,具有面向无连接,面向数据报特点,即使通信双方没有建立连接,也会传输数据,并且一次性发送全部的数据报,一次性接受全部的数据报。

Java 中基于UDP协议通信,主要使用 DatagramSocket 类来创建数据报套接字,并使用
DatagramPacket 作为发送或接收的UDP数据报。


针对一个客户端对服务器发出一次请求,服务器针对该请求给予响应流程如下:

在真实的网络环境中,一个服务器往往会给多个客户端提供响应。

举个实际的例子根据以上流程图理解一下,张三老铁使用手机百度浏览器搜索 “美女图片”,此时前端页面就会将这条搜索记录 “美女图片” 拿到后台打包成UDP 数据报,以请求的形式发给百度服务器,百度服务器拿到请求后,解析数据报查看:哦~ 要美女啊,我这有很多,于是将“本地”存储的美女图片作为 UDP 数据报的形式响应给请求端,百度浏览器拿到百度服务器响应的数据后,通过解析,将图片展示在张三的手机界面上。


二、UDP 数据报套接字编程

2.1  DatagramSocket API

DatagramSocket 是Socket 套接字基于UDP 协议来发送和接受数据报的类.

Datagram : 数据报

Socket : 说明这个对象是一个 Socket 对象

Socket 对象相当于操作系统一个特殊的文件,这个文件并非对应对应的硬盘上的某个数据存储区域,而是对应到,网卡这个硬件!!!

往 socket 对象中写数据,相当于通过网卡发送消息

从 socket 对象中读数据,相当于通过网卡接收消息

所以想要进行网络编程使得两个设备相互通信,就需要有 socket 文件这样的对象,借助这个 socket 文件对象来间接的操作网卡,操作系统基本设计思想:一切皆文件,为了简化系统内核的逻辑设计,socket 对象面向字节流读写


此处Socket 对象可以被客户端 / 服务端使用,服务器这边的 Socket 必须要关联一个具体的端口号,每个联网的设备在启动时或随机或指定都会绑定一个端口号,作为该应用程序的唯一标识,就相当于数据被你的设备接收,经解析需要知道这些数据需要交给那个应用程序处理。例如,qq 、微信没见过消息发串了的情况吧。

客户端这边可以不需要手动指定,系统会自动随机分配,端口号的取值范围是 [0, 65535]。

小于等于1024 的端口号,会提供给知名的服务器使用,不建议使用这一类。


socket 也是文件,用完了要关闭资源。


2.2  DatagramPacket API

DatagramPacket 类是用于基于UDP 协议的Socket 发送和接收的数据报。

只有两个参数的版本,不需要设计地址,通常用来接收消息。另一个多参数的版本需要显式的设置地址进去,通常要用来发送消息。


构造UDP 发送的数据报时,需要传入 socketAddress对象,这个对象可以使用 InetSocketAddress 来创建 。

InetSocketAddress API 的构造方法:


 三、基于UDP Socket 实现客户端,服务器程序

分析客户端的程序的功能:

1.发出请求(消息)

2. 等待服务器响应(回应)

3. 解析服务器的响应

分析服务端的程序的功能:
1. 尝试读取客户端的请求并解析

2. 根据客户端的请求,统筹响应的数据

3. 把响应返回到客户端


3.1 服务端程序设计

首先我们定义一个服务端的类:UdpEchoServer

定义一个 Socket 对象文件,与网卡交互。

//需要线定义一个 socket 对象
//通过网络通信,必须要使用 socket 对象
private DatagramSocket socket = null;

利用 UdpEchoServer类 的构造方法为 socket  构造,并指定需要绑定的端口号

  public UdpEchoServer(int serverPort) throws SocketException {
        //构造 socket 的同时,指定要的关联/ 绑定的端口
        socket = new DatagramSocket(serverPort);
  }

绑定一个端口,不一定能成功,如果某个端口已经被别的进程占用了,此时这里的绑定操作就会出错,同时一个主机上,一个端口,同一时刻,只能被一个进程绑定。所以这里会抛出异常。


定义一个启动方法:start() 

方法内部采用循环的方式,每次循环,做三件事:

1. 读取请求并解析,2. 根据请求计算响应,3. 把响应的结果写回客服端

public void start() throws IOException {
        System.out.println("服务器启动!");
        while (true) {
            // 每次循环,要做三件事情:
            // 1. 读取请求并解析
            // 构造接受请求的“空盒子”,指定盒子的大小 4096 字节
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
            // 数据从网卡上来的
            socket.receive(requestPacket);// 获取客户端的请求、

            //为了方便处理这个请求,把二进制数据转换成 String
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            // 2. 根据请求计算响应 调用方法
            String response = process(request);

            /* 3. 把响应结果写回客服端
            根据response 字符串,构造一个 DatagramPacket
            和请求 packet 不同,此处构造响应的时候,需要指定这个包要发给谁 */
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length, requestPacket.getSocketAddress());
            // response.getBytes() 转换为 byte二进制流
            // requestPacket 是从客户端这里收来的,getSocketAddress 就会得到客户端的 IP 和 端口
            socket.send(responsePacket);// 响应
            // 可以保存以下日志
            String now3 = df.format(System.currentTimeMillis()); // 返回当前系统时间
            try(Writer writer = new FileWriter("outPut.txt", true)) {
                writer.write(requestPacket.getAddress().toString() +
                        requestPacket.getPort() + " " + now3 +
                        " req: " + request + " resp:  " + response + "\n");
            }
            // 打印一下本次客户端与服务端的交互
            System.out.printf("[%s:%d] req: %s, resp: %s\n", requestPacket.getAddress().toString(),
                    requestPacket.getPort(), request, response);
        }
    }
 public static void main(String[] args) throws IOException {
        UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
        udpEchoServer.start();

    }

2. 根据客户端的请求,统筹响应的数据,我们将第二步计算响应以函数的方式封装实现,参数 request 请求我们已经转换为字符串了,所以我们就可以依据请求做出对应的处理了,如果是需要搜索什么,就可以根据请求的内容将服务器的中存储的被搜索内容作为响应返回给客户端,如果是互相发消息,那就需要根据请求判断需要发给谁,此时需要双方约定在请求中添加接收方的IP 和 端口,这样才能找到接收方,作为服务器端来讲就需要使用多线程的思想,每一个客户端发来请求都会分配一个线程来处理。

    public String process(String request) { //这里直接将客户端的请求,作为响应返回
        return "服务器响应:" + request;
    }

这个部分可以依据客户端的请求,进行对应的业务处理。


3.2 客户端程序设计

首先定义一个客户端的类:UdpEchoClient 

定义一个 Socket 对象文件,与网卡交互。

定义 serverIP 的成员变量,用于存储服务器端的IP 地址

定义 serverPort 的成员变量,用于存储服务器的端口号

private DatagramSocket socket = null;
private String serverIP = null; // IP
private int serverPort = 0; // 端口号 —— 代表进程的标识

利用 UdpEchoClient 类 的构造方法为 socket  构造,并为成员方法关联服务器的 IP 地址和端口

   //客户端启动,需要知道服务器在哪儿!!
    public UdpEchoClient(String serverIP, int serverPort) throws SocketException {
        //对于客户端来说,不需要显示关联端口
        // 不代表没有端口,而是系统自动分配了个空闲的端口
        socket = new DatagramSocket(); //获取随机端口号
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }

定义一个启动方法:start() 

方法内部采用循环的方式,每次循环,做4件事:

1. 从控制台获取用户输入的信息

2. 将获取的信息构造成 UDP 数据报,并向服务器发送请求

3. 客户端尝试获取读取服务器返回的响应

4. 将获取的的响应根据业务需求做进一步的处理

public void start() throws IOException {
        // 通过这个客户端可以多次和服务器进行交互
        System.out.println("客户端启动!");
        Scanner in = new Scanner(System.in);
        while (true) {
            //1.先从控制台,读取一个字符串过来
            //先打印一个提示符,提示用户要输入内容
            System.out.print("->");
            String request = in.next();

            //2. 把字符串构造成 UDP packet, 并进行发送
            DatagramPacket requestPacket = new DatagramPacket(
                    request.getBytes(),
                    request.getBytes().length,
                    //----如果参数为null,获得的是本机的IP地址
                    InetAddress.getByName(serverIP),// 确定主机的 IP 地址----在给定主机名的情况下确定主机的IP地址
                    serverPort);
            socket.send(requestPacket); //响应

            //3. 客户端尝试读取服务器返回的响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePacket);

            //4. 把响应的数据转换成 String 显示出来,利用 String 的构造方法转换
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            System.out.printf("req: %s, resp: %s\n", request, response);
        }
    }
 public static void main(String[] args) throws IOException {
        UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090);
        udpEchoClient.start(); // 启动客户端
    }

3.3 总结:

以上客户端服务器代码使用了 Socket “ 文件流”, 但是没有调用 close() 方法释放资源,是因为文件流会随着进程的关闭而关闭,但是在实际开发中一定要记得随手关闭哦~

启动客户端和服务器展示效果:

 以上操作流程执行图。

 一定是先启动服务器,再启动客户端,

UDP(User Datagram Protocol)是一个无连接的传输层协议,它不保证数据包可靠传输。UDP比TCP更快,而且在对网络延迟要求较低、对数据准确性要求不高的情况下使用。本文将讨论基于UDP Socket的客户端服务器开发总结。

UDP Socket

Socket是一种用于在计算机之间进行通信的 API(应用程序接口)。UDP Socket是基于UDP协议进行通信的套接字,它提供了一种快速发送和接收数据包的方法,但是与TCP不同,它不会重复数据或者检查是否有缺失的数据包。

编写UDP客户端的基本步骤如下:

  1. 创建一个UDP socket。
  2. 将要发送的数据打包到UDP数据包中。
  3. 使用UDP socket发送数据包到特定的IP地址和端口号。

编写UDP服务器的基本步骤如下:

  1. 创建一个UDP socket并监听特定的端口号。
  2. 接收客户端发送的数据包。
  3. 处理数据包,然后将响应打包到另一个UDP数据包中。
  4. 使用UDP socket向客户端发送响应数据包。

总结:

在使用UDP Socket进行客户端和服务器开发时,需要注意以下几点:

  • UDP不会保证数据包的可靠传输,因此需要在应用程序中处理数据包的丢失或者损坏情况。
  • 由于UDP没有连接状态,因此可以同时与多个客户端通信。
  • 在UDP通信中,需要指定目标地址和端口号。

好了,到这里,网络编程中的 基于UDP-Socket 实现客户端,服务器通信博主已经分享完了,希望对大家有所帮助,如有不妥之处欢迎批评指正。 

下期预告:TCP 协议

感谢每一个观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* 

遇见你,所有的星星都落在我的头上……

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

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

相关文章

Java中提升接口性能的一些方法

目录 1.使用线程池并行执行2.数据库优化2.1 小表关联大表2.2 反三大范式操作2.3 增加索引2.4 减小事务粒度2.5 读写分离、分库分表 3.拥抱缓存3.1 Redis3.2 内存缓存 4.锁和异步4.1 减小锁的粒度4.2 分布式锁 1.使用线程池并行执行 假如有一个接口的逻辑如下: 接口…

cadence遇到的问题

1、最烦人的,突然卡住。 设置grid卡住,导出libraries卡住,选择其他产品时卡住。 从微软拼音输入法改成美式键盘后能解决一些问题。但不能解决全部。 今天下载了搜狗输入法来替代微软自带输入法。效果奇佳,真的可以诶。 2、如果…

沁恒 CH32V208(一): CH32V208WBU6 评估板上手报告和Win10环境配置

目录 沁恒 CH32V208(一): CH32V208WBU6 评估板上手报告和Win10环境配置 CH32V208 CH32V208系列是沁恒32位RISC-V中比较新的一个系列, 基于青稞RISC-V4C内核, 最高144MHz主频, 64KB SRAM,128KB Flash, 供电电压2.5/3.3V. 这个型号的特点: 除了特有的硬件堆栈区、…

【C++11那些事儿(三)】

文章目录 一、可变参数模板1.1 概念引入1.2 递归函数方式展开参数包1.3 逗号表达式展开参数包1.4 可变参数模板在STL中的应用 二、包装器1.1 function1.2 bind 一、可变参数模板 1.1 概念引入 C11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板&#x…

链表的添加修改删除操作

public class HeroNodeDemo {public static void main(String[] args) {HeroNode hero1 new HeroNode(1, "松江");HeroNode hero2 new HeroNode(2, "武松");HeroNode hero3 new HeroNode(3, "及时雨");HeroNode hero4 new HeroNode(4, "…

AWVS-window版本安装

Acunetix Web Vulnerability Scanner(简称AWVS)是一款知名的网络漏洞扫描工具,它通过网络爬虫测试你的网站安全,检测流行安全漏洞。 一、下载 链接:https://pan.baidu.com/s/1GuLCmYBmhVYA2_qBwfjZhw 提取码&#x…

管家婆安装导致电脑蓝屏问题解决方案

安装完管家婆后,电脑蓝屏,重启还是蓝屏,这该怎么办? 导致的原因:因加密狗驱动不适配于Windows10系统,导致电脑蓝屏 修复方案:进入电脑安全模式(怎么进入问度娘)&#…

css奇淫巧计

1.input文本内容替换 -webkit-text-security:通过用形状替换字符,仅影响那些字段不是的typepassword 可选值:none (无),circle (圆圈),disc (圆形),square &a…

【STM32CubeMX】串口通信

前言 本文记录下我学习STM32CubeMX时的流程,方便以后回忆。本章记录串口通信。这里居然有玄学问题,给我整了好久,头都大了。可能也是我能力有限才有的吧,泪目。 目录 串口通信 串口通信 STM32CubeMX中的串口配置,配…

MiniGPT-4引领潮流,GPT-4提前发布图片阅读功能

ChatGPT中国站翻译自medium.com 让我们来看看如何玩Minigpt-4并将其应用到日常生活中。 今年三月,OpenAI 宣布了 GPT-4 的图像识别功能,这意味着 GPT 技术又被提升一个维度。-4 尚未发布给大众使用很长时间,所以终于有人忍不住了!…

由 ChatGPT 团队开发,堪称辅助神器!IntelliJ IDEA 神级插件

什么是Bito? 为什么要使用Bito? 如何安装Bito插件 如何使用Bito插件 什么是Bito? Bito是一款由ChatGPT团队开发的IntelliJ IDEA编辑器插件,旨在提高开发人员的工作效率。此插件强大之处在于它不仅可以帮助开发人员更快地提交…

vulnhub靶机sar

准备工作 下载连接:https://download.vulnhub.com/sar/sar.zip 下载完后解压,然后双击打开,VMware导入OVA 网络环境:DHCP、NAT 信息收集 主机发现 先扫描整个C段 192.168.100.132应该就是我们的目标 端口扫描 扫描目标主机…

3个经典线程同步问题

生产者消费者问题 问题描述 系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。生产者、消费者共享一个初始为空、大小为n的缓冲区 伪码描述 semaphore mutex 1;//互斥信…

Zabbix服务端监控目标主机的Web服务(网站的访问延迟)

zabbix服务端和目标主机的部署见上一篇文章: http://t.csdn.cn/XD5Hc Zabbix服务端监控目标主机 服务端启动zabbix服务后,在浏览器上访问:http://IP/zabbix 1.创建主机群主(名字自定义) 2.创建主机 主…

javaEE基于SSh学生选课系统

设计内容1. 搜集相关资料、作出功能需求分析; 2. 各个功能模块的基本功能大体如下: (1). 管理员模块 包括个人中心、专业管理、班级管理、课程管理、教师管理、选课管理。. (2).教师模块 包括个人中心、课程信息、出勤管理、成绩管理。 (3)…

大数据-玩转数据-netcat

Netcat(简称nc)是一款强大的命令行网络工具,用来在两台机器之间建立TCP/UDP连接,并通过标准的输入输出进行数据的读写。 一、Windows 下载安装 netcat(nc)命令 1、netcat(nc)下载地址: https://eternallybored.org/…

《程序员面试金典(第6版)》面试题 16.08. 整数的英语表示

题目描述 给定一个整数,打印该整数的英文描述。 示例 1: 输入: 123输出: “One Hundred Twenty Three” 示例 2: 输入: 12345输出: “Twelve Thousand Three Hundred Forty Five” 示例 3: 输入: 1234567输出: “One Million Two Hundred Thirty Four Thousand…

Kali 更换源(超详细,附国内优质镜像源地址)

1.进入管理员下的控制台。 2. 输入密码后点击“授权”。 3.在控制台内输入下面的内容。 vim /etc/apt/sources.list 4.敲击回车后会进入下面的页面。 5.来到这个页面后的第一部是按键盘上的“i”键,左下角出现“插入”后说明操作正确。 6.使用“#”将原本的源给注释…

武汉大学惯性导航课程合集【2021年秋】1.2 惯性器件的误差和标定

前提平台惯导NED与本地对齐,body系和navigation对齐。地表IMU感受到的是 朝天上的力【0,0,-9.8】和 赤道的【15deg/hr,0,0】或者北极 【0,0,-15deg/hr】或者【15cos纬度,0&#xff0…

「STM32入门」USART串口通信

通信 通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统 通信协议:制定通信的规则,通信双方按照协议规则进行数据收发 STM32常见的通信协议 本文将介绍USART 概念解释 TX、RX分别是Transmit和Receive的缩写&#xff0c…