当前位置: 首页 > news >正文

UDP客户端、服务端及简易聊天室实现 —— Java

UDP 协议(用户数据包协议)
UDP 是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接,简单来说,当客户端向接收端发送数据时,客户端不会确认接收端是否存在,就会发出数据。同样接收端在接收数据时,也不会向发送端反馈是否收到数据
由于使用 UDP 协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据传输
例如:视频会议通常采用 UDP 协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用 UDP 协议传送数据时,由于 UDP 的面向无连接性,不能保证数据的完整性,因此在传输重要数据是不建议使用 UDP 协议

客户端与服务器端图解

TCP 是基于字节流的传输层通信协议,所以 TCP 编程是基于 IO 流编程

Java:实现UDP协议发送/接收数据

UDP 通信编程
发送 数据
1..创建 DatagramSocket 对象
不传参,指定端口。(发送端口)
2.创建 DatagramPacket 对象
需传入指定的byte数组,长度,要发送的地址,接收的端口号。
3.发送数据
4.关闭

 客户端:

package com.lpy.socketdemo2;import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;public class SendDemo {public static void main(String[] args) throws IOException {// 创建 DatagramSocket 对象   DatagramSocket ds = new DatagramSocket();String str = "hello world";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 80;// 创建 DatagramPacket 对象 DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);// 发送数据ds.send(dp);// 关闭 ds.close();}
}
 接收 数据
  1. 创建 DatagramSocket 对象,指定接收用的端口号
  2. 创建 DatagramPacket 对象,用byte数组接收,指定接收长度
  3. 接收数据
  4. 解析数据

服务端:

package com.lpy.socketdemo3;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;public class ReceiveDemo {public static void main(String[] args) throws IOException {// 创建 DatagramSocket 对象,指定接收用的端口号DatagramSocket ds = new DatagramSocket(10086);byte[] bytes = new byte[1024];// 创建 DatagramPacket 对象,用byte数组接收,指定接收长度DatagramPacket dp = new DatagramPacket(bytes, bytes.length);// 接收数据ds.receive(dp);// 解析数据byte[] data = dp.getData();int len = dp.getLength();InetAddress address = dp.getAddress();int port = dp.getPort();System.out.println("接收到的数据" + new String(data, 0, len)); // // 接收到的数据hello worldSystem.out.println("该数据是从" + address + "这台电脑中的" + port + "端口发送出来的"); // // 该数据是从/127.0.0.1这台电脑中的65220端口发送出来的// 关闭ds.close();}
}

DatagramSocket类负责接收和发送数据报。每个DatagramSocket对象都会与一个本地端口绑定,在此端口监听发送过来的数据报。在客户程序中,一般由操作系统为DatagramSocket类分配本地端口,这种端口也被称为匿名端口。在服务器程序中,一般由程序显式地为DatagramSocket类指定本地端口。


send()方法可用于发送数据包,DatagramSocket的receive()方法负责接收一个数据报
值得注意的是,UDP提供不可靠的传输,如果数据报没有到达目的地,那么send()方法不会抛出任何异常,发送方程序就无法知道数据报是否被接收方接收到,除非双方通过应用层的特定协议来确保接收方未收到数据报时,发送方能重发数据报。 send()方法可能会抛出IOException,但是与java.uti.Socket相比,DatagramSocket的send()方法抛出IOException的可能性很小。如果发送的数据报超过了底层网络所支持的数据报的大小,就可能会抛出SocketException,它是IOException的子类。

在使用UDP实现Socket通信时,服务端与客户端都是使用DatagramSocket类,传输的数据要存放在DatagramPacket类中。 DatagramSocket类表示用来发送和接收数据报包的套接字。数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。在DatagramSocket上总是启用UDP广播发送。为了接收广播包,应该将DatagramSocket绑定到通配符地址。在某些实现中,将DatagramSocket绑定到一个更加具体的地址时广播包也可以被接收。

DatagramPacket类表示数据报包。数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。 DatagramSocket类中的public synchronized void receive(DatagramPacket p)方法的作用是从此套接字接收数据报包。当此方法返回时,DatagramPacket的缓冲区填充了接收的数据。数据报包也包含发送方的IP地址和发送方机器上的端口号,此方法在接收到数据报前一直阻塞。数据报包对象的length字段包含所接收信息的长度。如果发送的信息比接收端包关联的byte[]长度长,该信息将被截短。如果发送信息的长度大于65507,则发送端出现异常。
DatagramSocket类中的public void send(DatagramPacket p)方法的作用是从此套接字发送数据报包。
DatagramPacket包含的信息有:将要发送的数据及其长度、远程主机的IP地址和远程主机的端口号。 DatagramPacket类中的public synchronized byte[]getData()方法的作用是返回数据缓冲区。接收到的或将要发送的数据从缓冲区中的偏移量offset处开始,持续length长度。

在某些场合,一个DatagramSocket可能只希望与固定的另一个远程DatagramSocket通信。例如,NFS客户只接收来自与之通信的服务器的数据报。再例如,在网络游戏中,一个游戏玩家只接收他的游戏搭档的数据报。 从JDK1.2开始,DatagramSocket添加了一些方法,利用这些方法,可以使一个DatagramSocket只能与另一个固定的DatagramSocket交换数据报。
(1)public void connect(InetAddress host,int port) connect()方法实际上不建立TCP意义上的连接,但它能限制当前DatagramSocket只对参数指定的远程主机和UDP端口收发数据报。如果当前DatagramSocket试图对其他的主机或UDP端口发送数据报,send()方法就会抛出IllegalArgumentException。从参数以外的其他主机或UDP端口发送过来的数据报则被丢弃,程序不会得到任何通知,也不会抛出任何异常。
2)public void disconnect() disconnect()中止当前DatagramSocket已经建立的“连接”,这样,DatagramSocket就可以再次对任何其他主机和UDP端口收发数据报。
(3)public int getPort() 当且仅当DatagramSocket已经建立连接时,getPort()方法才返回DatagramSocket所连接的远程UDP端口,否则返回“-1”。
(4)public InetAddress getInetAddress() 当且仅当DatagramSocket已经建立连接时,getInetAddress()方法才返回DatagramSocket所连接的远程主机的IP地址,否则返回null。
(5)public SocketAddress getRemoteSocketAddress() 当且仅当DatagramSocket已经建立连接时,getRemoteSocketAddress()方法才返回一个SocketAddress对象,表示DatagramSocket所连接的远程主机以及端口的地址,否则返回null。

UDP客户程序通常只和特定的UDP服务器通信,因此可在UDP客户程序中把DatagramSocket与远程服务器连接。UDP服务器需要与多个UDP客户程序通信,因此在UDP服务器中一般不用对DatagramSocket建立特定的连接。
关闭DatagramSocket
DatagramSocket的close()方法会释放所占用的本地UDP端口。在程序中及时关闭不再需要的DatagramSocket,这是好的编程习惯。

DatagramSocket的选项
1.SO_TIMEOUT选项 ·设置该选项:public void setSoTimeout(int milliseconds) throws SocketException ·读取该选项:public int getSoTimeOut() throws SocketException DatagramSocket类的SO_TIMEOUT选项用于设定接收数据报的等待超时时间,单位为ms,它的默认值为0,表示会无限等待,永远不会超时。以下代码把接收数据报的等待超时时间设为3min:

if(socket.getTimeOut() == 0) socket.setTimeOut(60000*3);

DatagramSocket的setTimeout()方法必须在接收数据报之前执行才有效。当执行DatagramSocket的receive()方法时,如果等待超时,那么会抛出SocketTimeoutException,此时DatagramSocket仍然是有效的,尝试再次接收数据报。

2.SO_RCVBUF选项
·设置该选项:public void setReceiveBufferSize(int size) throws SocketException
·读取该选项:public int getReceiveBufferSize() throws SocketException
SO_RCVBUF表示底层网络的接收数据的缓冲区(简称接收缓冲区)的大小。对于有着较快传输速度的网络(比如以太网),较大的缓冲区有助于提高传输性能,因为可以在缓冲区溢出之前存储更多的入站数据报。与TCP相比,对于UDP,确保接收数据的缓冲区具有足够的大小更为重要,因为当缓冲区满后再到达的数据报会被丢弃。而TCP会在这种情况下要求重传数据,确保数据不会丢失。 此外,SO_RCVBUF还决定了程序接收的数据报的最大大小。在接收缓冲区中放不下的数据报会被丢弃。 setReceiveBufferSize(int size)方法设置接收缓冲区的大小,值得注意的是,许多网络都限定了接收缓冲区大小的最大值,如果参数size超过该值,那么setReceiveBufferSize(int size)方法所做的设置无效。getReceiveBufferSize()方法返回接收缓冲区的实际大小。

3.SO_SNDBUF选项
·设置该选项:public void setSendBufferSize(int size) throws SocketException
·读取该选项:public int getSendBufferSize() throws SocketException SO_SNDBUF表示底层网络的发送数据的缓冲区(简称发送缓冲区)的大小。setSendBufferSize(int size)方法设置发送缓冲区的大小,值得注意的是,许多网络都限定了发送缓冲区大小的最大值,如果参数size超过该值,那么setSendBufferSize(int size)方法所做的设置无效。getSendBufferSize()方法返回发送缓冲区的实际大小。

4.SO_REUSEADDR选项
·设置该选项:public void setResuseAddress(boolean on) throws SocketException
·读取该选项:public boolean getResuseAddress() throws SocketException
SO_REUSEADDR选项对于UDP Socket和TCP Socket有着不同的意义。对于UDP,SO_REUSEADDR决定多个DatagramSocket是否可以同时被绑定到相同的IP地址和端口。如果多个DatagramSocket被绑定到相同的IP地址和端口,那么到达该地址的数据报会被复制给所有的DatagramSocket。 setResuseAddress(boolean on)必须在DatagramSocket绑定到端口之前被调用,这意味着必须采用以下这个构造方法来创建DatagramSocket对象。

protected DatagramSocket(DatagramSocketImpl impl)
//此构造方法创建的DatagramSocket对象未与任何端口绑定

5.SO_BROADCAST选项
·设置该选项:public void setBroadCast(boolean on) throws SocketException
·读取该选项:public boolean getBroadCast() throws SocketException SO_BROADCAST选项决定是否允许对网络广播地址发送广播数据报。对于一个地址为192.168.5.*的网络,其本地网络广播地址为 192.168.5.255。UDP广播常被用于JXTA对等发现协议(JXTA Peer Discovery Protocol)、服务定位协议(Service Location Protocol)和DHCP动态主机配置协议(Dynamic Host Configuration Protocol)等协议。例如,如果需要和本地网中的服务器通信,但是预先不知道服务器的地址,就需要采用这些协议。 广播数据报一般只在本地网络中传播,路由器和网关一般不转发广播数据报。SO_BROADCAST选项的默认值为true。如果不希望发送广播数据报,那么可以调用DatagramSocket的setBroadCast(false)方法。

实现简易的通信聊天

客户端:

package com.lpy.socketdemo4;import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class Send {public static void main(String[] args) throws IOException {DatagramSocket ds = new DatagramSocket();Scanner sc = new Scanner(System.in);int port = 80;InetAddress address = InetAddress.getByName("127.0.0.1");while (true) {System.out.println("请输入发送的内容:");String str = sc.nextLine();byte[] bytes = str.getBytes("UTF-8");DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);ds.send(dp);if (str.equals("bye")) break;}ds.close();}
}

 服务端:

package com.lpy.socketdemo4;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class receive {public static void main(String[] args) throws IOException {DatagramSocket ds = new DatagramSocket(80);byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);while (true) {ds.receive(dp);byte[] data = dp.getData();int len = dp.getLength();String str = new String(data, 0, len, "UTF-8");System.out.println("由" + dp.getAddress().getHostAddress() + "主机" + dp.getPort() +"端口号发来了:");System.out.println(str);if (str.equals("bye")) {break;}}ds.close();}
}

效果如图: 

本次分享到此结束,觉得有所帮助的朋友点点关注点点赞! 

相关文章:

UDP客户端、服务端及简易聊天室实现 —— Java

UDP 协议(用户数据包协议) UDP 是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接,简单来说,当客户端向接收端发送数据时,客户端不会确认接收端是否存在,就会发出…...

下载安装nodejs npm jarn笔记

下载安装nodejs npm jarn笔记 下载 Node.js安装Node.js修改node全局路径安装yarn 下载 Node.js 下载Node.js 安装Node.js 双击下载的下来的.msi文件运行并安装一直点next。安装路径可以是默认也可自定义。安装完成后Node.js和npm就安装完成了 命令行输入: nod…...

Calibration相机内参数标定

1.环境依赖 本算法采用张正友相机标定法进行实现,内部对其进行了封装。 环境依赖为 ubuntu20.04 opencv4.2.0 yaml-cpp yaml-cpp安装方式: (1)git clone https://github.com/jbeder/yaml-cpp.git #将yaml-cpp下载至本地 &a…...

MySQL源码安装

安装MySQL ​ 本次安装使用的是绿色硬盘版本,无需额外安装依赖环境,比较简单 cd /opt tar -xf mysql安装包 mv 解压出的目录 /usr/local/mysql #创建程序用户 useradd -M -s /sbin/nologin mysql #mysql的主配置文件设定所属用户和组 chown -R mysql.m…...

gtest单元测试:进程冻结与恢复管理模块的单元测试实现

文章目录 1. 概要2. 进程管理接口详解2.1 进程冻结与恢复的基本概念2.2 进程查找与PID获取2.3 进程冻结与恢复的实现2.3.1 进程冻结2.3.2 进程恢复 2.4 进程终止2.5 进程状态监控与控制 3. dummy_process的设计与实现3.1 创建dummy_process脚本3.2 启动dummy_process3.3 终止du…...

Flutter动画详解第二篇之显式动画(Explicit Animations)

目录 前言 一、定义 1.AnimationController 1.常用属性 1. value 2. status 3. duration 2.常用方法 1.forward 2.reverse 3.repeat 4.stop 5. reset 6. animateTo(double target, {Duration? duration, Curve curve Curves.linear}) 7.animateBack(double ta…...

python常用模块(JSON与pickle、Os模块)

一、Open函数使用 在python中,open() 函数用于打开文件,并返回一个文件对象,同时支持读取和写入文件。 基本用法: file open(file_path, moder, encodingNone, newlineNone) 其中file_path表示的是文件的路径,可以…...

MMLab-dataset_analysis

数据分析工具 这里写目录标题 数据分析工具dataset_analysis.py数据可视化分析 benchmark.pybrowse_coco_json.pybrowse_dataset.pyOptimize_anchors mmyolo、mmsegmentation等提供了数据集分析工具 dataset_analysis.py 数据采用coco格式数据 根据配置文件分析全部数据类型或…...

艺术与技术的交响曲:CSS绘图的艺术与实践

在前端开发的世界里,CSS(层叠样式表)作为网页布局和样式的基石,其功能早已超越了简单的颜色和间距设置。近年来,随着CSS3的普及,开发者们开始探索CSS在图形绘制方面的潜力,用纯粹的代码创造出令…...

基于 JAVA 的旅游网站设计与实现

点击下载源码 塞北村镇旅游网站设计 摘要 城市旅游产业的日新月异影响着村镇旅游产业的发展变化。网络、电子科技的迅猛前进同样牵动着旅游产业的快速成长。随着人们消费理念的不断发展变化,越来越多的人开始注意精神文明的追求,而不仅仅只是在意物质消…...

【C++深度探索】二叉搜索树的全面解析与高效实现

🔥 个人主页:大耳朵土土垚 🔥 所属专栏:C从入门至进阶 这里将会不定期更新有关C/C的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 文章目录…...

Java实习记录 1 ——初入职场

Java实习记录 1 ——初入职场 引言正文收获 引言 在几个月的春招过程中,在完成学校学业的同时,进行投简历、笔试和面试。得益于较为扎实的技术基础,在暑假来临之际,找到了第一份实习工作。目前已入职将近半个月。记录一下实习经历…...

opencv—常用函数学习_“干货“_3

目录 八、图像拼接 水平拼接图像 (hconcat) 垂直拼接图像 (vconcat) 全景图像拼接 (Stitcher) 九、颜色通道及数据格式 转换图像的颜色空间 (cvtColor) 转换图像的数据类型 (convertTo) 分离和合并颜色通道 (split 和 merge) 提取和插入颜色通道 (extractChannel 和 in…...

用Docker来开发

未完成。。。 现在好像用Docker是越来越多了。之前其实也看过docker的原理,大概就是cgroup那些,不过现在就不看原理了,不谈理论,只看实际中怎么用,解决眼前问题。 用docker来做开发,其实就是解决的编译环境…...

从0开始的STM32HAL库学习2

外部中断(HAL库GPIO讲解) 今天我们会详细地学习STM32CubeMX配置外部中断,并且讲解HAL库的GPIO的各种函数。 准备工作: 1、STM32开发板(我的是STM32F103C8T6) 2、STM32CubeMx软件、 IDE: Keil软件 3、STM32F1xx/ST…...

【MySQL篇】Percona XtraBackup工具备份指南:常用备份命令详解与实践(第二篇,总共五篇)

💫《博主介绍》:✨又是一天没白过,我是奈斯,DBA一名✨ 💫《擅长领域》:✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux,也在扩展大数据方向的知识面✌️…...

Spock单元测试框架使用介绍和实践

背景 单元测试是保证我们写的代码是我们想要的结果的最有效的办法。根据下面的数据图统计,单元测试从长期来看也有很大的收益。 单元测试收益: 它是最容易保证代码覆盖率达到100%的测试。可以⼤幅降低上线时的紧张指数。单元测试能更快地发现问题。单元测试的性…...

web安全之跨站脚本攻击xss

定义: 后果 比如黑客可以通过恶意代码,拿到用户的cookie就可以去登陆了 分类 存储型 攻击者把恶意脚本存储在目标网站的数据库中(没有过滤直接保存),当用户访问这个页面时,恶意脚本会从数据库中被读取并在用户浏览器中执行。比如在那些允许用户评论的…...

TCP与UDP的理解

文章目录 UDP协议UDP协议的特点UDP的应用以及杂项 TCP协议TCP协议段格式解释和TCP过程详解确认应答机制 -- 序号和确认序号以及6位标志位中的ACK超时重传机制连接管理机制 与标志位SYN,FIN,ACK滑动窗口与16位窗口大小流量控制拥塞控制延迟应答捎带应答和面向字节流粘包问题TCP异…...

有效应对服务器遭受CC攻击的策略与实践

分布式拒绝服务(DDoS)攻击,尤其是其中的HTTP洪水攻击或称为CC攻击(Challenge Collapsar),是当今互联网安全领域的一大挑战。这种攻击通过大量合法的请求占用大量网络资源,导致服务器无法正常响应…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

leetcode73-矩阵置零

leetcode 73 思路 记录 0 元素的位置&#xff1a;遍历整个矩阵&#xff0c;找出所有值为 0 的元素&#xff0c;并将它们的坐标记录在数组zeroPosition中置零操作&#xff1a;遍历记录的所有 0 元素位置&#xff0c;将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...