摘要:現在在本機同一局域網的一臺機器和阿里云主機上都運行然后啟動發送端接收端接收結果可以看到每個接收端都正確的接收了發送端發送的消息。
今天的主角是 UDP(User Datagram Protocol,用戶數據報協議)。
我們都知道 TCP 是一種可靠的協議 —— 首先客戶端和服務端需要建立連接(三次“握手”),數據發送完畢需要斷開連接(四次“揮手”);如果發送數據時數據損壞或者丟失,那么 TCP 會重新發送。保證可靠的代價就是效率的降低(建立連接和斷開連接就需要時間,保證數據的可靠性也需要額外的消耗)。與 TCP 相對應,UDP 是面向無連接的協議,并且它不保證數據是否會到達,也不保證到達的數據是否準確和數據順序是否正確 —— 所以相比于 TCP, UDP 的速度很快。在 需要不建立連接即可發送數據 的系統,或者 保證最快的傳輸速度比每一位數據都正確更重要 的系統(如視頻會議,丟失某個數據包只是一個畫面或者聲音的小干擾)中,UDP 才是正確的選擇。實際上,在同一個網段,或者在信號很好的局域網,UDP 是非常可靠的。
在 Java 中使用 UDP 時關鍵的兩個類分別是:DatagramSocket 和 DatagramPacket。
DatagramPacket 表示數據包,而 DatagrameSocket 用來發送和接收數據包。
發送數據包時:
因為 UDP 協議并不需要建立連接,所以我們將數據(byte數組)放入 DatagramPacket 之后,還需要將目的地(IP地址和端口)放入到 DatagramPacket 中 —— DatagramSocket 的 send(DatagramPacket packet) 方法根據 packet 中指定目的地,將其包含的數據往這個目的地發送。至于數據是否能(準確)到達目的地,DatagramSocket 并不關心。
接收數據包時:
DatagramSocket 在接收數據包時,我們需要為其指定一個監聽的端口。當有包含了接收端機器 IP 地址和 DatagramSocket 所監聽端口的數據包到達時,DatagramSocket 的 receive(DatagramPacket packet) 方法便會對數據包進行接收,并將接收到的數據包填入到 packet 中。
現在讓我們來實踐 DatagramSocket 和 DatagramPacket:
因為 UDP 沒有服務端和客戶端之分,所以我們把兩端分別定義為 發送端 和 接收端。
發送端代碼:
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class UDPSender { private static final int RECVER_LISTENING_PORT = 9999; public static void main(String[] args) throws Exception { Listmessages = new ArrayList<>(12); for (int i = 0; i < 4; i++) { String msgBody = (i == 3 ? "" : "Hello UDP-" + i); DatagramPacket msg0 = parseMsg( msgBody, "127.0.0.1", RECVER_LISTENING_PORT); // 發送給本機 DatagramPacket msg1 = parseMsg( msgBody, "192.168.3.3", RECVER_LISTENING_PORT); // 發送給同一局域網的一臺機器 DatagramPacket msg2 = parseMsg( msgBody, "120.77.**.***", RECVER_LISTENING_PORT); // 120.77.**.*** 是我阿里云主機的公網 IP 地址 // JDK1.5 時 Collections 添加的 addAll 方法,可以一次往某個集合中添加多個元素 Collections.addAll(messages, msg0, msg2, msg1); } startSending(messages); } private static void startSending(List messages) throws IOException, InterruptedException { // 無參構造的 DatagramSocket 會隨機選擇一個端口進行監聽 // 因為此時 DatagramSocket 的作用是發送,所以無需顯式指定固定端口 try (DatagramSocket socket = new DatagramSocket()) { System.out.println("隨機給發送端分配的端口為:" + socket.getLocalPort() + " "); for (DatagramPacket msg : messages) { socket.send(msg); // 發送數據包 int recverPort = msg.getPort(); InetAddress recverAddr = msg.getAddress(); System.out.printf("消息已經發送 -> (%s:%d) ", recverAddr.getHostAddress(), recverPort); Thread.sleep(500); // 設定 每隔 0.5 秒發送一個消息 } } } private static DatagramPacket parseMsg(String msgBody, String addr, int port) throws UnknownHostException { byte[] msgData = msgBody.getBytes(); DatagramPacket msg = new DatagramPacket( msgData, 0, msgData.length, // 數據從位置 0 開始,長度為 msgData.length InetAddress.getByName(addr), port); // 目的地 地址為 addr,監聽端口為 port return msg; } }
接收端代碼:
import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UDPReceiver { private static final int LISTENING_PORT = 9999; private static final int BUFFER_SIZE = 512; public static void main(String[] args) throws Exception { byte[] buffer = new byte[BUFFER_SIZE]; DatagramPacket msg = new DatagramPacket(buffer, buffer.length); try (DatagramSocket socket = new DatagramSocket(LISTENING_PORT)) { System.out.println("接收端已經啟動... "); while (true) { socket.receive(msg); // 接收數據包 String msgBody = new String( msg.getData(), msg.getOffset(), msg.getLength()); if (msgBody.isEmpty()) { // 發現接收的消息是空字符串("")便跳出循環 break; } int senderPort = msg.getPort(); InetAddress senderAddr = msg.getAddress(); System.out.printf("發送端 地址和端口 -> (%s:%d) ", senderAddr.getHostAddress(), senderPort); System.out.println("發送端 發送的消息 -> " + msgBody + " "); } } System.out.println("接收端已經關閉。"); } }
現在 在本機、同一局域網的一臺機器和阿里云主機上都運行 UDPReceiver:
然后啟動發送端 UDPSender:
接收端接收結果:
可以看到每個接收端都正確的接收了發送端發送的消息。
(本機 和 局域網機器 顯示的發送端的端口(49756)是一致的,但是遠程機器即阿里云主機顯示的(4802)卻與他們不一致——這個問題留給有興趣的讀者自己思考)
雖然 UDP 是不可靠的協議,但是因為它不需要建立連接,效率更快,所以在 需要不建立連接即可發送數據 的系統(比如本文的例子),或者 保證最快的傳輸速度比每一位數據都正確更重要 的系統中,我們應該使用 UDP。當然,基于 UDP 我們同樣可以開發出可靠的協議——數據包的正確與否可以交給應用程序來判斷,如果有問題接收端便提示發送端重新發送。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69833.html
摘要:具備發送和接受功能,在進行傳輸時,需要明確一個是發送端,一個是接收端。指定發送端口,不指定系統會隨機分配。傳輸兩個端點的建立連接后會有一個傳輸數據的通道,這通道稱為流,而且是建立在網絡基礎上的流,稱之為流。 端口:物理端口:邏輯端口: 用于標識進程的邏輯地址,不同進程的標識;有效端口:0~65535,其中0~1024系統使用或保留端口。 java 中ip對象:InetAddress....
摘要:三端口與套接字端口指一臺計算機只有單一的連接到網絡的物理連接,所以的數據都通過此連接對內對外送達特定的計算機,這就是端口。三程序設計由上面可知基于的信息傳遞速度更快。接收數據包使用創建數據包套接字,綁定指定端口。 服務器 網絡 客戶機 第一部分 一.局域網與因特網 服務器是指提供信息的計算機或程序,...
摘要:那沒有建立連接的情況下,發現房間這個功能是怎么實現的呢首先,既然手機處于局域網中,那么根據手機當前在局域網的地址和子網掩碼,就可以獲得這個局域網內所有機器的地址的范圍。 記得以前我們使用類似快牙這些文件分享工具的時候,一開始就是先在 手機A 上創建一個房間,然后連接上 手機A WiFi 熱點的其他手機(即這些手機處于一個局域網內)就可以發現到這個房間并加入到這個房間里面,然后就可以互相...
摘要:更多資料請看編程之編程協議用戶數據報協議是無連接的不可靠的無序的速度快進行數據傳輸時,首先將要傳輸的數據定義成數據報,大小限制在,在數據報中指明數據索要達到的主機地址和端口號,然后再將數據報發送出去類表示數據報包類進行端到端通信的類服務器端 更多資料請看:https://www.yuque.com/shizhiy... Java Socket編程之UDP編程 UDP協議(用戶數據報協...
摘要:應用層主要負責應用程序的協議,例如協議協議等。在計算機中,不同的應用程序是通過端口號區分的。區別在于,中只有發送端和接收端,不區分客戶端與服務器端,計算機之間可以任意地發送數據。 01網絡模型 *A:網絡模型 TCP/IP協議中的四層分別是應用層、傳輸層、網絡層和鏈路層,每層分別負責不同的通信功能,接下來針對這四層進行詳細地講解。 鏈路層:鏈路層是用于定義物理傳輸通道,通常是對...
閱讀 1454·2021-11-24 09:39
閱讀 3632·2021-09-29 09:47
閱讀 1580·2021-09-29 09:34
閱讀 3074·2021-09-10 10:51
閱讀 2541·2019-08-30 15:54
閱讀 3222·2019-08-30 15:54
閱讀 878·2019-08-30 11:07
閱讀 1011·2019-08-29 18:36