网络编程-UDP套接字
文章目录
- UDP/TCP协议简介
- 两种协议的联系与区别
- Socket是什么
- UDP的SocketAPI
- DatagramSocket
- DatagramPacket
- 使用UDP模拟通信
- 服务器端
- 客户端
- 测试
- 完整测试代码
UDP/TCP协议简介
两种协议的联系与区别
TCP和UDP其实是传输层的两个协议的内容, 差别非常大, 对于我们的Java来说, JVM对操作系统提供的关于网络的 API 进行了封装, 提供了两套的API
下面是网络连接中的一些特点
- 有/无连接: 抽象的概念, 虚拟的, 逻辑上的连接, 而不是物理的连接, 其实就是看, 在网络通信的过程中, 是否保存了对端的一些信息, 比如说IP, 端口号之类的
- 可靠传输/不可靠传输: 网络传输的过程中, 传输的信息是十分容易丢失的, 不可能100%的到达, 这里说的可靠传输还是不可靠传输是指的是, 尽可能的到达, 可靠传输, 发送消息之后, 会尽可能的提高传输的成功率, 如果出现了丢包的问题, 对面也能感知到, 但是对于不可靠传输, 发送消息之后就不管了, 只是简单的发送了数据
- 面向字节流/数据报: 指的是传输的方式, 有的协议使用字节流进行内容的传输, 容易粘包, 支持任意长度, 有的协议使用数据报进行内容的传输, 不存在粘包, 但是有长度限制
- 全双工/半双工: 一个通信的链路, 支持双向的通信, 能读, 也能写, 但是有的通信的协议只支持单向的通信, 要么读, 要么写
下面是 UDP 协议和 TCP 协议的特点的声明
| UDP | TCP |
|---|---|
| 无连接 | 有连接 |
| 不可靠传输 | 可靠传输 |
| 面向数据报 | 面向字节流 |
| 全双工 | 全双工 |
Socket是什么
可以理解为是一个网卡的代言人, 在计算机中来说, 文件其实是一种广义的概念, 网卡我们也抽象为一种Socket文件, 所以操作网卡的流程中, 是与文件的操作是差不多的, 对网卡的操作, 其实是对Socket这种文件类型的操作, 也会占用文件操作符表(文件操作中的一种资源), 所以也要及时关闭
- 打开 -> 读写 -> 关闭
UDP的SocketAPI
DatagramSocket
上面我们说过, 每一种套接字都有自己的一套 API, 而UDP的操作网卡的 API 就是 DatagramSocket
常见的构造方法

上图的两个构造方法是我们常用的两个方法
- 第一个是不带端口号的版本, 所以定义之后, 会给当前的程序随机分配一个端口号(一般用于客户端)
- 第二个参数是给一个指定的端口号(一般用于服务器端)
- 如果一台服务器上有多个UDP程序使用同一个端口号, 那就会出现问题, 端口号冲突, 但是如果同一台计算机上不同协议的程序使用同一个端口号不会冲突, 比如一个UDP程序使用端口号9090, 另一个TCP程序也使用9090, 这种情况就不会冲突
常用的方法

send方法是发送构造好的DatagramPacket对象(其实就是数据报), receive是一种输出型函数的机制, 通常是传入一个空的DatagramPacket对象, 然后把接收到的内容填入到这个对象内部, 如果没有客户端发送数据, 该方法就会陷入阻塞等待阶段

close方法, 关闭该套接字
观察这个类的继承结构

该类继承了AutoCloseable接口, 所以也支持try-with-resource机制
DatagramPacket
该类本质上是一个数据报
常见的构造方法

我们在之前就说过, UDP是一种无连接的协议, 也就是在网卡层面是不保存对端的信息的, 那我们要如果知道数据发送给哪一台机器呢 ? 实质上就是通过DatagramPacket来实现的, 这个数据报通常保存了对端的信息, 而传输的内容是通过字符数组来保存的, InetAddress其实是IP地址的信息, port是对端的端口号, SocketAddress可以理解为是InetAddress和port的结合, 里面既有IP信息还有端口号信息
常见的方法

注意:
对于一个数据报对象来说, 里面存储的地址的信息, 不仅包含接收方的地址信息, 还保存着发送方的地址信息, 所以想要在服务器端做出响应的时候, 对于发送的地址, 是从接收到的DatagramPacket对象中获取到的, 因为里面也保存了客户端的地址信息
getAddress获取的是IP地址, 既可以是发送端的, 也可以是接收端的getPort获取的是端口号, 同上getSocketAddress获取的是完整的地址信息, 同上getLength获取的是接收到的数据的真实长度(以字节计)
比如下面的代码

这种情况下返回的就是发送端的地址信息
在比如服务器给客户端返回结果的时候, 使用接收到的DatagramPacket对象的getAddress, getPort, getSocketAddress方法, 此时得到的就是发送方(也就是客户端)的地址信息
所以, 获取到的是哪一端的地址信息要看实际的情况
使用UDP模拟通信
关于计算机通信的机制, 我们之前的版块涉及到一点, 大致流程如下

服务器端
写一个执行翻译的服务器
创建网卡还有构造方法
// 创建一个网卡对象private DatagramSocket serverSocket = null;// 构造方法(服务器端固定端口号)public UdpServer(int port) throws SocketException {serverSocket = new DatagramSocket(port);}
start方法, 启动服务器, 不断接收用户的请求, 处理并响应
这里我们只是简单模拟一下, 真实的业务场景中, 这里的逻辑是相当相当复杂的, 所以处理时间可能会很长, 所以如果此时有别的客户端想请求的话, 那就有可能得不到及时的响应, 所以我们此时可以采用多线程的技术, 使用线程池来优化, 具体代码我们最后的完整代码会给出
// start方法开启服务器public void start() throws IOException {// 记录日志, UDP 服务器上线System.out.println("UDP服务器上线");// 使用while循环不断接收客户端的请求while(true){// 1. 读取请求(使用一个空数据报来接收客户端数据, 输出型函数)DatagramPacket request = new DatagramPacket(new byte[4096], 0, 4096);serverSocket.receive(request);// 2. 解析请求并处理String req = new String(request.getData(), 0, request.getLength());String resp = process(req);// 3. 返回响应(发送处理的结果)DatagramPacket responce = new DatagramPacket(resp.getBytes(), 0, resp.getBytes().length,request.getSocketAddress());serverSocket.send(responce);// 4. 记录日志信息System.out.printf("[%s, %d] req:%s resp:%s\n", request.getAddress().toString(), request.getPort(), req, resp);}}
处理的核心逻辑
// 对请求处理的逻辑private static Map<String, String> chineseToEnglish = new HashMap<>();static {chineseToEnglish.put("小猫", "cat");chineseToEnglish.put("小狗", "dog");chineseToEnglish.put("小鹿", "fawn");chineseToEnglish.put("小鸟", "bird");}private String process(String req){return chineseToEnglish.getOrDefault(req, "未收录该词条");}
客户端
关于客户端其实和服务器端差不多, 也是发送请求和接收响应的逻辑
创建网卡, 构造方法, 还有创建变量来保存对端的地址信息(构造数据报使用)
// 创建网卡private DatagramSocket clientSocket = null;// 创建变量保存对端信息private InetAddress serverInet = null;private int serverPort = 0;// 构造方法(客户端一般是随机的端口号)public UdpClient(String iNetAddr, int serverPort) throws UnknownHostException, SocketException {this.serverPort = serverPort;this.serverInet = InetAddress.getByName(iNetAddr);clientSocket = new DatagramSocket();}
start方法, 请求并响应
while(sc.hasNext()){// 1. 输入并发送请求String req = sc.next();DatagramPacket request = new DatagramPacket(req.getBytes(), 0, req.getBytes().length, serverInet, serverPort);clientSocket.send(request);// 2. 等待请求响应DatagramPacket responce = new DatagramPacket(new byte[4096], 0, 4096);clientSocket.receive(responce);String resp = new String(responce.getData(), 0, responce.getLength());// 3. 输出响应结果System.out.println(resp);}
测试
下面是上面的代码的运行测试截图


完整测试代码
客户端
package net_demo1.net_demo03;import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpClient {// 创建网卡private DatagramSocket clientSocket = null;// 创建变量保存对端信息private InetAddress serverInet = null;private int serverPort = 0;// 构造方法(客户端一般是随机的端口号)public UdpClient(String iNetAddr, int serverPort) throws UnknownHostException, SocketException {this.serverPort = serverPort;this.serverInet = InetAddress.getByName(iNetAddr);clientSocket = new DatagramSocket();}// start方法, 启动客户端public void start() throws IOException {// 创建一个Scanner对象接收用户输入Scanner sc = new Scanner(System.in);// 使用while循环来请求并接收响应while(sc.hasNext()){// 1. 输入并发送请求String req = sc.next();DatagramPacket request = new DatagramPacket(req.getBytes(), 0, req.getBytes().length, serverInet, serverPort);clientSocket.send(request);// 2. 等待请求响应DatagramPacket responce = new DatagramPacket(new byte[4096], 0, 4096);clientSocket.receive(responce);String resp = new String(responce.getData(), 0, responce.getLength());// 3. 输出响应结果System.out.println(resp);}}public static void main(String[] args) throws IOException {UdpClient udpClient = new UdpClient("127.0.0.1", 9090);udpClient.start();}
}
服务器端
package net_demo1.net_demo03;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class UdpServer {// 创建一个网卡对象private DatagramSocket serverSocket = null;// 构造方法(服务器端固定端口号)public UdpServer(int port) throws SocketException {serverSocket = new DatagramSocket(port);}// start方法开启服务器public void start() throws IOException {// 记录日志, UDP 服务器上线System.out.println("UDP服务器上线");// 创建一个线程池ExecutorService executorService = Executors.newCachedThreadPool();// 使用while循环不断接收客户端的请求while (true) {// 1. 读取请求(使用一个空数据报来接收客户端数据, 输出型函数)DatagramPacket request = new DatagramPacket(new byte[4096], 0, 4096);serverSocket.receive(request);// 这里的改进, 由于我们处理的时间可能会很长, 如果此时有别的客户端也请求了, 那就可能造成数据丢失// 所以我们使用线程池的技术, 通过多线程来执行任务executorService.execute(() -> {String req = new String(request.getData(), 0, request.getLength());String resp = process(req);// 3. 返回响应(发送处理的结果)DatagramPacket responce = new DatagramPacket(resp.getBytes(), 0, resp.getBytes().length,request.getSocketAddress());try {serverSocket.send(responce);} catch (IOException e) {e.printStackTrace();}// 4. 记录日志信息System.out.printf("[%s, %d] req:%s resp:%s\n",request.getAddress().toString(), request.getPort(), req, resp);});}}// 对请求处理的逻辑private static Map<String, String> chineseToEnglish = new HashMap<>();static {chineseToEnglish.put("小猫", "cat");chineseToEnglish.put("小狗", "dog");chineseToEnglish.put("小鹿", "fawn");chineseToEnglish.put("小鸟", "bird");}private String process(String req) {return chineseToEnglish.getOrDefault(req, "未收录该词条");}public static void main(String[] args) throws IOException {UdpServer udpServer = new UdpServer(9090);udpServer.start();}
}相关文章:
网络编程-UDP套接字
文章目录 UDP/TCP协议简介两种协议的联系与区别Socket是什么 UDP的SocketAPIDatagramSocketDatagramPacket 使用UDP模拟通信服务器端客户端测试 完整测试代码 UDP/TCP协议简介 两种协议的联系与区别 TCP和UDP其实是传输层的两个协议的内容, 差别非常大, 对于我们的Java来说, …...
Web 音视频(一)基础知识
前言 阅读后续文章或开始使用 WebAV 处理音视频数据之前,需要一点点背景知识。 本篇主要简单介绍音视频最基础的知识,以及 WebCodecs 的核心 API。 视频结构 视频文件可以理解为容器包含了元数据和编码数据(压缩的音频或视频)…...
数字化时代,传统代理模式的变革之路
在数字化飞速发展的今天,线上线下融合(O2O)成了商业领域的大趋势。这股潮流,正猛烈冲击着传统代理模式,给它带来了新的改变。 咱们先看看线上线下融合现在啥情况。线上渠道那是越来越多,企业纷纷在电商平台…...
Linux 高级路由与流量控制-用 tc qdisc 管理 Linux 网络带宽
大家读完记得觉得有帮助记得关注和点赞!!! 此分享内容比较专业,很多与硬件和通讯规则及队列,比较底层需要有技术功底人员深入解读。 Linux 的带宽管理能力 足以媲美许多高端、专用的带宽管理系统。 1 队列࿰…...
【数据库知识】PostgreSQL介绍
PostgreSQL介绍 概述一、起源与发展二、特性与功能三、PL/pgSQL语言四、应用场景五、配置与优化 核心概念一、基础数据结构二、数据操作三、高级特性四、应用场景 多版本控制MVCC说明一、MVCC的基本概念二、MVCC的实现原理三、MVCC的工作流程四、MVCC的优势五、MVCC的局限性 可…...
软考,沟通管理
软件沟通管理 已发送、巳收到、已理解、己认可、已转化为积极的行动 有效的沟通活动和成果创建具有如下3个基本属性:①沟通目的明确;②尽量了解沟通接收方,满足其需求及偏好;③监督并衡量沟通的效果。 让干系人参加项目会议&…...
Linux 存储设备和 Ventoy 启动盘制作指南
一、Linux 存储设备基础知识 1. 设备路径(/dev) 设备路径是 Linux 系统中物理存储设备的唯一标识,类似设备的"身份证号"。 命名规则解析 /dev/sda: /dev:device(设备)的缩写&…...
Android SystemUI——CarSystemBar车载状态栏(九)
上一篇文章我们介绍了车载开发中的 CarSystemUI,而车载开发中的状态栏也被 CarSystemBar 所取代,这里我们就来看看一下车载系统中的状态栏——CarSystemBar。 一、车载状态栏创建 1、CarSystemBar 源码位置:/packages/apps/Car/SystemUI/src/com/android/systemui/car/sy…...
多级缓存 JVM进程缓存
目录 多级缓存 1.什么是多级缓存 2.JVM进程缓存 2.1 导入案例 2.2 初识Caffeine 2.3 实现JVM进程缓存 2.3.1 需求 2.3.2 实现 3.Lua语法入门 3.1 初识Lua 3.1 HelloWorld 3.2.变量和循环 3.2.1 Lua的数据类型 3.2.3 循环 3.3 条件控制、函数 3.3.1 函数 3.3.2 条件控制 3.3.3 案…...
使用Chrome和Selenium实现对Superset等私域网站的截图
最近遇到了一个问题,因为一些原因,我搭建的一个 Superset 的 Report 功能由于节假日期间不好控制邮件的发送,所以急需一个方案来替换掉 Superset 的 Report 功能 首先我们需要 Chrome 浏览器和 Chrome Driver,这是执行数据抓取的…...
如何让大语言模型更好地理解科学文献?
论文地址:https://arxiv.org/pdf/2408.15545 引言 科学文献的理解对于提取目标信息和获取洞察至关重要,这显著推动了科学发现。尽管大语言模型(LLMs)在自然语言处理方面取得了显著成功,但在科学文献理解方面仍面临挑战…...
anaconda安装和环境配置
文章目录 一、Anaconda下载1.从官网直接下载:2.从镜像站中下载: 二、Anaconda安装三、检测是否有Anaconda配置anaconda环境 四、 Anaconda创建多个python环境(方便管理项目环境)1.查看conda有哪些环境2.创建python3.6的环境3.激活…...
Python基础学习(五)文件和异常
文件操作, 使用代码 来读写文件 1, 可以将数据保存到文件中, 2, 自动化, 测试数据在文件中保存的, 从文件中读取测试数据,进行自动化代码的执行 1.文件 文件: 可以存储在长期存储设备(硬盘, U盘)上的一段数据即为文件 1, 计算机只认识 二进制数据(0 和 1) 2, 所有的文件在计算…...
Mono里运行C#脚本29—mono_trampolines_init
一、概念解释 在计算机编程中,trampoline 通常是一段代码,它起到一个中间跳转的作用。它就像一个跳板,程序可以先跳转到这个跳板上,然后再从跳板跳转到最终的目的地。这种技术在许多不同的场景中都有应用,以下是一些主要方面: 函数调用方面: 当涉及到不同执行环境或不…...
从语音识别到图像识别:AI如何“看”和“听”
引言 随着人工智能技术的不断进步,AI的“听”和“看”能力正变得越来越强大。从语音识别到图像识别,AI不仅能够通过声音与我们互动,还能通过视觉理解和分析周围的世界。这些技术不仅改变了我们与机器的交互方式,也在各行各业中带…...
vue3+ts+uniapp 微信小程序(第一篇)—— 微信小程序定位授权,位置信息权限授权
文章目录 简介一、先看效果1.1 授权定位前,先弹出隐私协议弹框1.2 上述弹框点击同意,得到如下弹框1.3 点击三个点,然后点设置 1.4 在1.2步骤下,无论同意或者拒绝 二、manifest.json 文件配置三、微信公众平台配置3.1 登录进入微信…...
回归算法、聚类算法、决策树、随机森林、神经网络
这也太全了!回归算法、聚类算法、决策树、随机森林、神经网络、贝叶斯算法、支持向量机等十大机器学习算法一口气学完!_哔哩哔哩_bilibili 【线性回归、代价函数、损失函数】动画讲解_哔哩哔哩_bilibili 14分钟详解所有机器学习算法:…...
[Qt]系统相关-文件操作-QFile、QFileInfo类以及相关操作函数
目录 一、Qt文件系统 1.Qt文件系统的介绍 2.Qt文件类 二、Qt文件的操作 1.文件的打开 2.文件的读写操作 3.关闭操作 4.接口使用案例 5.获取文件的相关属性 三、文件的分类 1.文本文件 2.二进制文件 3.二者的区别 一、Qt文件系统 1.Qt文件系统的介绍 文件操作是所…...
C#高级:用Csharp操作鼠标和键盘
一、winform 1.实时获取鼠标位置 public Form1() {InitializeComponent();InitialTime(); }private void InitialTime() {// 初始化 Timer 控件var timer new System.Windows.Forms.Timer();timer.Interval 100; // 设置为 100 毫秒,即每 0.1 秒更新一次timer.…...
Mac 使用 GVM 管理多版本 Go 环境
使用 GVM 管理多版本 Go 环境 在本文中,我们将使用 gvm(Go Version Manager)工具管理本地多个 Go 语言版本。gvm 功能类似于 Python 的 Anaconda,可以方便地切换不同版本的 Go 环境,非常适合需要多版本开发与测试的场…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
