网络编程 05:UDP 连接,UDP 与 TCP 的区别,实现 UDP 消息发送和接收,通过 URL 下载资源

一、概述

记录时间 [2025-09-02]

前置文章

网络编程 01:计算机网络概述,网络的作用,网络通信的要素,以及网络通信协议与分层模型

网络编程 02:IP 地址,IP 地址的作用、分类,通过 Java 实现 IP 地址的信息获取

网络编程 03:端口的定义、分类,端口映射,通过 Java 实现了 IP 和端口的信息获取

网络编程 04:TCP连接,客户端与服务器的区别,实现 TCP 聊天及文件上传,Tomcat 的简单使用


本文讲述网络编程相关知识——UDP 连接,包括 UDP 的核心特点,UDP 与 TCP 的区别,以及在 Java 中实现 UDP 消息发送和接收,通过 URL 下载资源等。



二、UDP

1. UDP 的核心特点

UDP(User Datagram Protocol,用户数据报协议)是一种简单的、无连接的、不可靠的传输层协议。

  • 无连接
    • UDP 发送数据之前不需要先建立连接,减少了通信的延迟。
  • 不可靠交付
    • UDP 不提供任何机制来确认数据是否成功到达目的地,也不保证数据包的送达顺序。
  • 无拥塞控制
    • UDP 以恒定的速率发送数据,而不管网络是否拥堵,容易丢包。这对于网络整体稳定性可能是个缺点,但对于需要恒定速率的应用却是优点。
  • 数据报结构
    • UDP 保留了应用程序定义的消息边界。如果发送方发送了 5 个 UDP 数据报,接收方将会收到 5 个独立的数据报。
    • 而 TCP 则是一个字节流,应用程序需要自己解析消息的开始和结束。

2. UDP 与 TCP 的区别

通过将 UDP 与 TCP 对比来更好地理解它:

特性TCP (传输控制协议)UDP (用户数据报协议)
连接面向连接的无连接的
通信前必须先建立连接(三次握手)无需建立连接,直接发送数据
可靠性可靠的不可靠的
确保数据按序、完整地送达,有重传机制不保证数据送达,也不保证顺序
传输速度相对较慢(由于握手、确认、重传等开销)非常快(开销极小)
数据流字节流,无消息边界数据报,有消息边界
拥塞控制有复杂的拥塞控制算法无拥塞控制
应用场景网页浏览(HTTP)、电子邮件(SMTP)、文件传输(FTP)视频流、语音通话、在线游戏、DNS查询

3. UDP 在 Java 的关键类

在 Java 中,使用 UDP 协议进行网络通信主要涉及两个类:DatagramPacket 和 DatagramSocket。

  • DatagramPacket
    • 用于发送和接收数据报包的套接字;
    • 表示一个数据报包,用于存储要发送或接收的数据;
    • 包含了数据本身以及目标地址(IP 地址和端口号)。
  • DatagramSocket:用于发送和接收 DatagramPacket 的套接字。
    • 表示数据报包,包含数据和目标地址信息;
    • 用于发送时指定数据和目标地址;
    • 用于接收时提供缓冲区存储接收到的数据。

在这里插入图片描述



在这里插入图片描述



三、UDP 消息发送和接收

注意:UDP 中没有明确的客户端、服务端的概念,也不需要建立双向连接。我们在这里把发消息的称为发送端,接收消息的称为接收端。


1. 简单发送和接收

发送端

数据包 package 中包含:数据(字节 byte 类型),数据的长度(起始,结束), 对方 ip,对方端口。


import java.net.*;// 发送端
public class UdpSendDemo01 {public static void main(String[] args) throws Exception {// 1. 建立一个 socket, 开放端口DatagramSocket socket = new DatagramSocket();// 2. 准备一个数据包String msg = "这是一个数据包";InetAddress inetAddress = InetAddress.getByName("127.0.0.1");// 数据包, 数据的长度起始, 结束, 对方ip, 对方端口DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, inetAddress, 9000);// 3. 发送数据包socket.send(packet);System.out.println("Message sent to the server.");// 4. 关闭资源socket.close();}
}

接收端

接收包的程序要先打开,只有开着才能收到消息。

因为 UDP 只管发,不会去管接收端有没有准备好的。


import java.net.*;// 接收端
public class UdpReceiveDemo01 {public static void main(String[] args) throws Exception {// 1. 开放端口DatagramSocket socket = new DatagramSocket(9000);// 2. 接收数据包byte[] buffer = new byte[1024];DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);// 阻塞接收socket.receive(packet);// 3. 查看数据包System.out.println(packet.getAddress().getHostAddress());System.out.println(new String(packet.getData(), 0, packet.getLength()));// 4. 关闭资源socket.close();}
}

2. 循环发送和接收

在简单 UDP 消息发送的基础上,给程序增加循环,实现 UDP 消息循环发送和接收。

并增加判断条件:当发送过来的内容是 bye 时,程序结束。


发送端


import java.io.*;
import java.net.*;public class UdpSender {public static void main(String[] args) throws Exception {// 1. 开放端口DatagramSocket socket = new DatagramSocket(8888);// 2. 装包// 从键盘输入到控制台 System.in, 控制台读取// 用 BufferedReader 去读键盘输入到控制台的内容BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));while (true) {// 读一整行String data = reader.readLine();// 转成字节流, socket 发的是字节流byte[] dataBytes = data.getBytes();DatagramPacket packet = new DatagramPacket(dataBytes, 0, dataBytes.length, new InetSocketAddress("localhost", 6666));// 3. 发包socket.send(packet);// 本地退出if (data.equals("bye")) {break;}}// 4. 关闭资源socket.close();}
}

接收端

发过来的内容是字节 byte 类型的,要转换成字符串 String 类型。


import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UdpReceiver {public static void main(String[] args) throws Exception {// 1. 开放端口DatagramSocket socket = new DatagramSocket(6666);// 准备一个容器byte[] container = new byte[1024];while (true) {// 2. 读包DatagramPacket packet = new DatagramPacket(container, 0, container.length);// 阻塞接收包socket.receive(packet);// 3. 输出包// 包是字节流, 转成 stringbyte[] data = packet.getData();String receiveData = new String(data, 0, packet.getLength());// 输出内容System.out.println(receiveData);// 远程退出if (receiveData.equals("bye")) {break;}}// 4. 关闭资源socket.close();}
}


四、UDP 多线程在线咨询

特点:互发消息。

在了解 UDP 发送、接收消息的逻辑后,我们来实现如下程序功能。

  • 相当于一个咨询平台:学生向老师咨询问题,老师给出答复。
  • 接收端、发送端是两个多线程。
  • 老师端、学生端是两个用户,他们既可以发消息,也可以接收消息。

更多多线程相关的知识,请参考 - 这篇文章

这里,通过实现 Runnable 接口来创建线程。


1. 接收端

接收端用于接收 UDP 消息。


import java.io.IOException;
import java.net.*;public class TalkReceive implements Runnable {DatagramSocket socket = null;// 接收端的 portprivate int port;// 消息从哪里来private String msgFrom;public TalkReceive(int port, String msgFrom) {this.port = port;this.msgFrom = msgFrom;try {// 1. 开放端口this.socket = new DatagramSocket(this.port);} catch (SocketException e) {e.printStackTrace();}}@Overridepublic void run() {// 准备一个容器byte[] container = new byte[1024];while (true) {try {// 2. 读包DatagramPacket packet = new DatagramPacket(container, 0, container.length);// 阻塞接收包socket.receive(packet);// 3. 输出包// 包是字节流, 转成 Stringbyte[] data = packet.getData();String receiveData = new String(data, 0, packet.getLength());// 输出内容System.out.println(msgFrom + ": " + receiveData);// 断开连接, 远程退出if (receiveData.equals("bye")) {break;}} catch (IOException e) {e.printStackTrace();}}// 4. 关闭资源socket.close();}
}

2. 发送端

发送端用于发送 UDP 消息。


import java.io.*;
import java.net.*;public class TalkSend implements Runnable {DatagramSocket socket = null;BufferedReader reader = null;// 接收的地址 (接收 ip, 接收 port)private String toIP;private int toPort;// 从哪里来private int fromPort;public TalkSend(String toIP, int toPort, int fromPort) {this.fromPort = fromPort;this.toIP = toIP;this.toPort = toPort;try {// 1. 开放端口this.socket = new DatagramSocket(this.fromPort);// 从键盘输入到控制台 System.in, 控制台读取// 用 BufferedReader 去读键盘输入到控制台的内容reader = new BufferedReader(new InputStreamReader(System.in));} catch (SocketException e) {e.printStackTrace();}}@Overridepublic void run() {try {while (true) {// 2. 装包// 读一整行String data = reader.readLine();// 转成字节流, socket 发的是字节流byte[] dataBytes = data.getBytes();DatagramPacket packet = new DatagramPacket(dataBytes, 0, dataBytes.length, new InetSocketAddress(toIP, toPort));// 3. 发包socket.send(packet);// 本地退出if (data.equals("bye")) {break;}}} catch (IOException e) {e.printStackTrace();}// 4. 关闭资源socket.close();}
}

3. 老师端

模拟老师的操作:

  • 给学生发消息(创建发送端的多线程)
  • 接收来自学生的消息(创建接收端的多线程)

public class TalkTeacher {public static void main(String[] args) {// 启动多线程// 把消息发送到 localhost 的 8888 端口// 8888 是学生的 Receive 开放端口// Send 方开放的端口用不上,Receive 方开放的端口才有用new Thread(new TalkSend("localhost", 8888, 5555)).start();// 开放 9999 端口,接收来自学生的消息new Thread(new TalkReceive(9999, "student")).start();}
}

4. 学生端

模拟学生的操作:

  • 给老师发消息(创建发送端的多线程)
  • 接收来自老师的消息(创建接收端的多线程)

public class TalkStudent {public static void main(String[] args) {// 启动多线程// 把消息发送到 localhost 的 9999 端口// 9999 是老师的 Receive 开放端口new Thread(new TalkSend("localhost", 9999, 7777)).start();// 开放 8888 端口,接收来自老师的消息new Thread(new TalkReceive(8888, "teacher")).start();}
}


五、URL 下载网络资源

1. URL 概述

URL 格式

URL(Uniform Resource Locator,统一资源定位符) 是用于指定互联网上资源(如网页、图像、文件等)位置和访问方式的一种字符串。

通俗地说,它就是我们在浏览器地址栏里输入的 “网址”。


一个完整的 URL 由多个部分组成,通常遵循以下格式:

scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]// example
https://www.example.com:8080/products/index.html?category=electronics&id=42#specs

具体的部分,内容解释如下:

其中,www.example.com 是域名,可以通过 DNS 域名解析服务解析成对应的 IP 地址

部分例子说明
Scheme(方案)https://指定用于访问资源的协议。常见的有 httphttpsftpmailtofile。它告诉浏览器或应用程序使用哪种规则来获取资源。
Authority(授权部分)www.example.com:8080通常包含主机名 Host ** 和端口 Port**。
Host(主机)www.example.com资源所在服务器的域名或 IP 地址。
Port(端口):8080HTTP 默认端口是 80,HTTPS 是 443。如果使用默认端口,通常在 URL 中省略
Path(路径)/products/index.html指定服务器上资源的具体位置,类似于文件系统中的文件路径。
Query(查询字符串)?category=electronics&id=42用于向服务器传递额外的参数。以 ? 开头,包含多个键值对(key=value),键值对之间用 & 分隔。
Fragment(片段)#specs也称为 “锚点”,它指向资源内部的某个特定部分,如 HTML 页面中的一个标题。片段不会发送到服务器,仅在浏览器内部使用。

URL 编码

URL 只能使用有限的 ASCII 字符集,任何包含非 ASCII 字符(如中文)或特殊字符(如空格、&=)的 URL 都需要进行编码。

URL 编码也称为 “百分号编码”。

例如,空格被编码为 %20,中文 “中国” 被编码为 %E4%B8%AD%E5%9B%BD


通过 Java 查看 URL

在 Java 中,java.net.URL 类用于表示和解析 URL。它提供了许多有用的方法来分解和操作 URL 的各个部分。

通过 Java 来查看 URL 的各个部分。


import java.net.MalformedURLException;
import java.net.URL;public class URLDemo01 {public static void main(String[] args) throws MalformedURLException {// exampleURL url = new URL("https://www.example.com:8080/products/index.html?category=electronics&id=42#specs");// 协议System.out.println(url.getProtocol());// 主机ip、域名System.out.println(url.getHost());// 端口System.out.println(url.getPort());// 文件路径System.out.println(url.getPath());// 全路径: 路径+参数System.out.println(url.getFile());// 参数System.out.println(url.getQuery());}
}

对应的输出结果:

https
www.example.com
8080
/products/index.html
/products/index.html?category=electronics&id=42
category=electronics&id=42

2. 下载 URL 资源

在 上一篇 中,讲述了如何启动 Tomcat 并访问部署的资源。

例如,访问自定义资源:webapps 目录下的 test 中的 hello.txt 文件。

用到的其实就是一个 URL:

http://localhost:8080/test/hello.txt

接下来,我们来下载这个 URL 指向的网络资源。

  • 给出资源下载地址;
  • 连接到这个资源;
  • 通过流下载;
  • 通过文件管道处理资源,保存资源。

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;public class URLDown {/*本地 tomcat 中有这样一个文件http://localhost:8080/test/hello.txt通过 URL 下载下来*/public static void main(String[] args) throws Exception {// 1. 下载地址URL url = new URL("http://localhost:8080/test/hello.txt");// 2. 连接到这个资源 HTTPHttpURLConnection connection = (HttpURLConnection) url.openConnection();// 通过流下载InputStream is = connection.getInputStream();// 文件管道处理下载下来的数据FileOutputStream fos = new FileOutputStream(new File("NetStudy/hello.txt"));byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer)) != -1) {// 写出这个数据fos.write(buffer, 0, len);}// 3. 关闭资源, 断开连接fos.close();is.close();connection.disconnect();}}

同理可得,网络上的资源也可以这么下载,输入 URL 即可。

无论是文本、图片、视频、音频,还是其他类型的文件。

可以尝试一下:

// 下载图片
URL url = new URL("https://i-blog.csdnimg.cn/direct/728b14801d3f4400bad0905bfdba34be.jpeg");// 文件管道处理下载下来的数据
FileOutputStream fos = new FileOutputStream(new File("NetStudy/bfdba34be.jpeg"));


参考资料

狂神说 - 网络编程:https://www.bilibili.com/video/BV1LJ411z7vY

Java 8 帮助文档:https://docs.oracle.com/javase/8/docs/api/

多线程 02:线程实现,创建线程的三种方式,通过多线程下载图片案例分析异同(Thread,Runnable,Callable):https://blog.csdn.net/Sareur_1879/article/details/141029891

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

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

相关文章

告别线缆束缚!AirDroid Cast 多端投屏,让分享更自由

AirDroid Cast 是一款功能强大的跨平台投屏应用,能够轻松实现手机、电脑之间以及手机之间的屏幕共享与控制。无论是工作演示、在线教学还是游戏直播,AirDroid Cast 都能提供流畅稳定的投屏体验。 1. 下载与安装 您可以通过以下链接下载 AirDroid Cast&…

从零开始学大模型之大模型训练流程实践

大模型训练流程实践 本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型开发 学习视频/籽料/面试题 都在这>>Github<< >>Gitee<< 6.1 模型预训练 在上一章&#xff0c;我们逐步拆解了 LLM 的模型结构及训练过程&#xff0c;从零手…

一文从零部署vLLM+qwen0.5b(mac本地版,不可以实操GPU单元)

第一步&#xff1a;下载anaconda for mac https://zhuanlan.zhihu.com/p/350828057 知乎保姆级教程 https://www.anaconda.com/docs/getting-started/anaconda/install#macos-linux-installation 下载地址 第二步&#xff1a;部署vllm的虚拟环境 https://www.53ai.com/news/Op…

Go语言Range用法全解析

引言Go 语言中的 range 关键字是集合遍历的核心语法结构&#xff0c;它提供了一种高效且类型安全的方式来迭代各种数据结构。range 的设计完美体现了 Go 语言的工程哲学 - 通过最小化的语法提供最大化的功能。标准库中的许多关键组件&#xff08;如 sync.Map、bufio.Scanner 等…

mysql进阶语法(视图)

1、视图概念 是从一个或多个表中导出来的表&#xff0c;它是一种虚拟存在的表&#xff0c;表的结构和数据都依赖于基本表 应用场景&#xff1a; 多个地方用到同样的查询结果该查询结果用到复杂的select语句 视图优点&#xff1a; 简化查询语句&#xff1a;简化用户的查询操作&a…

编程范式:提升抽象能力的思维工具

这是一个编程中的核心概念&#xff0c;它代表了编写程序的一套基本风格、方法论和哲学。学习不同的编程范式&#xff0c;就像学习用不同的工具和思维方式来解决问题&#xff0c;能极大地提升你作为程序员的抽象能力和解决问题的能力。一、什么是编程范式&#xff1f;编程范式 是…

阿里云-基于通义灵码实现高效 AI 编码 | 1 | 在 Visual Studio Code 中安装和使用灵码

文章目录一、在 Visual Studio Code 中安装和使用灵码1.1 准备工作1.2 在 Visual Studio Code 安装通义灵码1.3 登录阿里云账号免费个人运维知识库&#xff0c;欢迎您的订阅&#xff1a;literator_ray.flowus.cn 一、在 Visual Studio Code 中安装和使用灵码 本安装步骤适用于…

WordPress搭建个人网站(Linux版)

WordPress搭建个人网站&#xff0c;使用Linux系统。我需要详细说明整个过程&#xff0c;包括环境准备、安装步骤、配置优化等。首先&#xff0c;用户可能对Linux不太熟悉&#xff0c;所以需要从基础开始&#xff0c;比如选择合适的Linux发行版&#xff0c;如Ubuntu或CentOS。然…

ES模块(ESM)、CommonJS(CJS)和UMD三种格式

vite的build.lib配置生成了三种格式&#xff1a;ES模块&#xff08;ESM&#xff09;、CommonJS&#xff08;CJS&#xff09;和UMD。它们的主要区别和适用场景如下&#xff1a; ES模块&#xff08;.mjs&#xff09;&#xff1a; 使用现代JavaScript的模块语法&#xff08;import…

2026届IC秋招联芸科技IC面经(完整面试题)

联芸科技2026届数字IC后端面经数字后端培训实战项目六大典型后端实现案例 首先是自我介绍。这个每家公司必备环节。这部分内容需要自己提前准备&#xff0c;避免太过紧张影响发挥。 数字IC后端经典笔试题IC秋招笔试题之时序报告解析 1&#xff09;拿到netlist和sdc后你会如何…

一维水动力模型有限体积法(四):高级实现——平衡源项、边界条件与算法总成

引言 成功实现一个稳定且精确的水动力学模型&#xff0c;关键在于妥善处理源项和边界条件。这两个环节是数值格式产生非物理振荡和误差的主要来源。本章将详细介绍“守恒-平衡”&#xff08;well-balanced&#xff09;格式的核心技术&#xff0c;以及通过“虚拟单元”实现各类物…

VAE(变分自动编码器)技术解析

VAE&#xff08;Variational Auto-Encoder, 变分自动编码器&#xff09;1、VAE的结构为什么使用重参数化&#xff1f;2、VAE的代码实现1.重构损失&#xff08;Reconstruction Loss&#xff09;2.KL散度&#xff08;Kullback-Leibler Divergence Loss&#xff09;1&#xff09;E…

嵌入式单片机---串口通信及相关通信技术

一、通信方式分类&#xff08;一&#xff09;按数据传输线路数量划分&#xff1a;串行通信与并行通信类别定义特点并行通信多个比特同时通过并行线进行传输优点&#xff1a;传输速率较高&#xff1b;缺点&#xff1a;占用大量芯片资源串行通信将数据拆分成一个个比特&#xff0…

Elasticsearch面试精讲 Day 8:聚合分析与统计查询

【Elasticsearch面试精讲 Day 8】聚合分析与统计查询 文章标签&#xff1a;Elasticsearch, 聚合查询, 统计分析, Aggregations, 面试, 大数据, 搜索引擎, 后端开发, 数据分析 文章简述&#xff1a; 本文是“Elasticsearch面试精讲”系列的第8天&#xff0c;聚焦聚合分析与统计…

HTML HTML基础(2)

1.开发者文档W3C官网&#xff1a; www.w3c.org W3School&#xff1a; www.w3school.com.cn MDN&#xff1a; developer.mozilla.org —— 推荐。2.排版标签标签名标签含义单 / 双 标签h1 ~ h6标题双p段落双div没有任何含义&#xff0c;用于整体布局双(1). h1 最好写一个&#x…

spring.profiles.active配置的作用

1. spring.profiles (或文件名中的 ?)&#xff1a;定义配置的名称这是声明一段配置属于哪个 Profile。在同一个 application.yml 中&#xff1a;使用 spring.profiles 键来为一个配置段打上标签。yamlspring:profiles: dev # 【定义】这个配置段的名称是‘dev’ server:port: …

【开题答辩全过程】以 高校教室管理系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

Aurobay EDI 需求分析:OFTP2 与 EDIFACT 驱动的汽车供应链数字化

Aurobay 是由吉利汽车集团与沃尔沃汽车集团合资成立的动力系统公司&#xff0c;总部位于瑞典哥德堡。其供应链系统广泛采用 EDI&#xff08;电子数据交换&#xff09;技术进行标准化通信与业务协作。通过严谨的 EDI 传输规范&#xff0c;其与供应商之间构建了高效、安全的数据交…

yolov8环境配置:从安装到卸载,从入门到放弃。

yolov8环境配置&#xff1a;从安装到卸载&#xff0c;从入门到放弃。 先讲安装再到删除。 前置环境安装&#xff1a;Conda 这里我选用MiniConda 使用清华的镜像安装&#xff1a;https://mirror.tuna.tsinghua.edu.cn/anaconda/miniconda/ 直接安装到C盘&#xff08;免得后续…

神马 M63S+ 438T矿机评测:SHA-256算法高效能挖矿利器

在加密货币的挖矿世界里&#xff0c;硬件设备的性能直接影响着矿工的挖矿效率与收益。而对于选择比特币&#xff08;BTC&#xff09;与比特币现金&#xff08;BCH&#xff09;等基于SHA-256算法的矿工来说&#xff0c;矿机的算力、功耗、能效比等参数无疑是至关重要的。在这篇文…