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

网络编程-UDP套接字

文章目录

  • UDP/TCP协议简介
    • 两种协议的联系与区别
    • Socket是什么
  • UDP的SocketAPI
    • DatagramSocket
    • DatagramPacket
  • 使用UDP模拟通信
    • 服务器端
    • 客户端
    • 测试
  • 完整测试代码

UDP/TCP协议简介

两种协议的联系与区别

TCP和UDP其实是传输层的两个协议的内容, 差别非常大, 对于我们的Java来说, JVM对操作系统提供的关于网络的 API 进行了封装, 提供了两套的API


下面是网络连接中的一些特点

  • 有/无连接: 抽象的概念, 虚拟的, 逻辑上的连接, 而不是物理的连接, 其实就是看, 在网络通信的过程中, 是否保存了对端的一些信息, 比如说IP, 端口号之类的
  • 可靠传输/不可靠传输: 网络传输的过程中, 传输的信息是十分容易丢失的, 不可能100%的到达, 这里说的可靠传输还是不可靠传输是指的是, 尽可能的到达, 可靠传输, 发送消息之后, 会尽可能的提高传输的成功率, 如果出现了丢包的问题, 对面也能感知到, 但是对于不可靠传输, 发送消息之后就不管了, 只是简单的发送了数据
  • 面向字节流/数据报: 指的是传输的方式, 有的协议使用字节流进行内容的传输, 容易粘包, 支持任意长度, 有的协议使用数据报进行内容的传输, 不存在粘包, 但是有长度限制
  • 全双工/半双工: 一个通信的链路, 支持双向的通信, 能读, 也能写, 但是有的通信的协议只支持单向的通信, 要么读, 要么写

下面是 UDP 协议和 TCP 协议的特点的声明

UDPTCP
无连接有连接
不可靠传输可靠传输
面向数据报面向字节流
全双工全双工

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 处理音视频数据之前&#xff0c;需要一点点背景知识。 本篇主要简单介绍音视频最基础的知识&#xff0c;以及 WebCodecs 的核心 API。 视频结构 视频文件可以理解为容器包含了元数据和编码数据&#xff08;压缩的音频或视频&#xff09;…...

数字化时代,传统代理模式的变革之路

在数字化飞速发展的今天&#xff0c;线上线下融合&#xff08;O2O&#xff09;成了商业领域的大趋势。这股潮流&#xff0c;正猛烈冲击着传统代理模式&#xff0c;给它带来了新的改变。 咱们先看看线上线下融合现在啥情况。线上渠道那是越来越多&#xff0c;企业纷纷在电商平台…...

Linux 高级路由与流量控制-用 tc qdisc 管理 Linux 网络带宽

大家读完记得觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 此分享内容比较专业&#xff0c;很多与硬件和通讯规则及队列&#xff0c;比较底层需要有技术功底人员深入解读。 Linux 的带宽管理能力 足以媲美许多高端、专用的带宽管理系统。 1 队列&#xff0…...

【数据库知识】PostgreSQL介绍

PostgreSQL介绍 概述一、起源与发展二、特性与功能三、PL/pgSQL语言四、应用场景五、配置与优化 核心概念一、基础数据结构二、数据操作三、高级特性四、应用场景 多版本控制MVCC说明一、MVCC的基本概念二、MVCC的实现原理三、MVCC的工作流程四、MVCC的优势五、MVCC的局限性 可…...

软考,沟通管理

软件沟通管理 已发送、巳收到、已理解、己认可、已转化为积极的行动 有效的沟通活动和成果创建具有如下3个基本属性&#xff1a;①沟通目的明确&#xff1b;②尽量了解沟通接收方&#xff0c;满足其需求及偏好&#xff1b;③监督并衡量沟通的效果。 让干系人参加项目会议&…...

Linux 存储设备和 Ventoy 启动盘制作指南

一、Linux 存储设备基础知识 1. 设备路径&#xff08;/dev&#xff09; 设备路径是 Linux 系统中物理存储设备的唯一标识&#xff0c;类似设备的"身份证号"。 命名规则解析 /dev/sda&#xff1a; /dev&#xff1a;device&#xff08;设备&#xff09;的缩写&…...

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等私域网站的截图

最近遇到了一个问题&#xff0c;因为一些原因&#xff0c;我搭建的一个 Superset 的 Report 功能由于节假日期间不好控制邮件的发送&#xff0c;所以急需一个方案来替换掉 Superset 的 Report 功能 首先我们需要 Chrome 浏览器和 Chrome Driver&#xff0c;这是执行数据抓取的…...

如何让大语言模型更好地理解科学文献?

论文地址&#xff1a;https://arxiv.org/pdf/2408.15545 引言 科学文献的理解对于提取目标信息和获取洞察至关重要&#xff0c;这显著推动了科学发现。尽管大语言模型&#xff08;LLMs&#xff09;在自然语言处理方面取得了显著成功&#xff0c;但在科学文献理解方面仍面临挑战…...

anaconda安装和环境配置

文章目录 一、Anaconda下载1.从官网直接下载&#xff1a;2.从镜像站中下载&#xff1a; 二、Anaconda安装三、检测是否有Anaconda配置anaconda环境 四、 Anaconda创建多个python环境&#xff08;方便管理项目环境&#xff09;1.查看conda有哪些环境2.创建python3.6的环境3.激活…...

Python基础学习(五)文件和异常

文件操作, 使用代码 来读写文件 1, 可以将数据保存到文件中, 2, 自动化, 测试数据在文件中保存的, 从文件中读取测试数据,进行自动化代码的执行 1.文件 文件: 可以存储在长期存储设备(硬盘, U盘)上的一段数据即为文件 1, 计算机只认识 二进制数据(0 和 1) 2, 所有的文件在计算…...

Mono里运行C#脚本29—mono_trampolines_init

一、概念解释 在计算机编程中,trampoline 通常是一段代码,它起到一个中间跳转的作用。它就像一个跳板,程序可以先跳转到这个跳板上,然后再从跳板跳转到最终的目的地。这种技术在许多不同的场景中都有应用,以下是一些主要方面: 函数调用方面: 当涉及到不同执行环境或不…...

从语音识别到图像识别:AI如何“看”和“听”

引言 随着人工智能技术的不断进步&#xff0c;AI的“听”和“看”能力正变得越来越强大。从语音识别到图像识别&#xff0c;AI不仅能够通过声音与我们互动&#xff0c;还能通过视觉理解和分析周围的世界。这些技术不仅改变了我们与机器的交互方式&#xff0c;也在各行各业中带…...

vue3+ts+uniapp 微信小程序(第一篇)—— 微信小程序定位授权,位置信息权限授权

文章目录 简介一、先看效果1.1 授权定位前&#xff0c;先弹出隐私协议弹框1.2 上述弹框点击同意&#xff0c;得到如下弹框1.3 点击三个点&#xff0c;然后点设置 1.4 在1.2步骤下&#xff0c;无论同意或者拒绝 二、manifest.json 文件配置三、微信公众平台配置3.1 登录进入微信…...

回归算法、聚类算法、决策树、随机森林、神经网络

这也太全了&#xff01;回归算法、聚类算法、决策树、随机森林、神经网络、贝叶斯算法、支持向量机等十大机器学习算法一口气学完&#xff01;_哔哩哔哩_bilibili 【线性回归、代价函数、损失函数】动画讲解_哔哩哔哩_bilibili 14分钟详解所有机器学习算法&#xff1a;…...

[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 毫秒&#xff0c;即每 0.1 秒更新一次timer.…...

Mac 使用 GVM 管理多版本 Go 环境

使用 GVM 管理多版本 Go 环境 在本文中&#xff0c;我们将使用 gvm&#xff08;Go Version Manager&#xff09;工具管理本地多个 Go 语言版本。gvm 功能类似于 Python 的 Anaconda&#xff0c;可以方便地切换不同版本的 Go 环境&#xff0c;非常适合需要多版本开发与测试的场…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...