網絡編程 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
英文地址,請注明出處:http://en.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;礦機的算力、功耗、能效比等參數無疑是至關重要的。在這篇文…