目錄
UDP協議
Java中的UDP通信
DatagramSocket
DatagramPacket
UDP客戶端-服務端代碼實現
UDP協議
對于UDP協議,這里簡單做一下介紹:
在TCP/IP協議簇中,用戶數據報協議(UDP)是傳輸層的一個主要協議之一,它與傳輸控制協議(TCP)一起構成了互聯網的基礎。UDP具有以下幾個主要特點:
- 無連接:UDP是一個無連接的協議,這意味著在通信之前不需要建立連接。每個數據包獨立傳輸,沒有握手過程。這使得UDP的傳輸延遲較低,適合需要快速傳輸數據的應用場景。
- 不可靠傳輸:UDP不保證數據的可靠傳輸。數據包可能會丟失、重復或亂序到達。協議本身不提供錯誤檢測和重傳機制。如果需要可靠性,必須在應用層實現。
- 面向報文:UDP是面向報文的協議。發送方將數據分成獨立的報文,每個報文包含完整的消息。接收方按報文接收數據,報文的邊界在接收時保持不變。
- 低開銷:由于UDP沒有連接建立、維護和終止的開銷,也沒有復雜的錯誤控制和流量控制機制,其報頭信息較少,僅包含源端口、目標端口、長度和校驗和。這使得UDP的開銷非常低,適合需要高效傳輸的應用。
- 支持廣播和多播:UDP支持廣播和多播,這意味著可以將數據包發送到一個或多個網絡中的所有主機。這在某些網絡應用中非常有用,例如視頻流和在線游戲。
- 實時性好:由于沒有連接建立和維護的開銷,加上較低的協議處理時間,UDP適合實時性要求高的應用,如視頻會議、語音通信和在線游戲。
- 簡單性:UDP協議相對簡單,實現和使用都比較方便。應用程序可以直接在UDP之上構建,并根據需要添加錯誤處理、重傳等機制。
適用場景
- 實時應用:如視頻流、語音通信、在線游戲等,要求低延遲和實時性,數據丟失影響較小。
- 簡單查詢服務:如DNS查詢,發送一個請求并期望快速響應,偶爾的丟包可以通過重試解決。
- 廣播和多播:如網絡發現、服務公告等,需要將消息發送給多個主機。
Java中的UDP通信
市面上大部分Java應用存在著大量的通信交流的需求,那了解了UDP協議的相關信息和使用場景后,對于Java程序我們該如何來實現通信呢?
在Java中實現UDP通信涉及兩個主要類:
DatagramSocket
和DatagramPacket
。
DatagramSocket
DatagramSocket
類用于創建和管理UDP套接字。它負責發送和接收數據包,并提供了基本的網絡通信功能。
主要功能包括:
- 綁定到特定的IP地址和端口。
- 發送和接收
DatagramPacket
。 - 管理網絡連接的基本設置(例如超時、緩沖區大小)。
主要方法
DatagramSocket()
: 創建一個綁定到任意可用端口的套接字。DatagramSocket(int port)
: 創建一個綁定到指定端口的套接字。DatagramSocket(int port, InetAddress laddr)
: 創建一個綁定到指定端口和本地地址的套接字。send(DatagramPacket p)
: 發送數據包。receive(DatagramPacket p)
: 接收數據包。close()
: 關閉套接字。
更多詳細的方法和參數講解可以查看oracle官方的API文檔:
DatagramSocket (Java SE 17 & JDK 17) (oracle.com)
這里是中文版本的:
DatagramSocket - Java17中文文檔 - API參考文檔 - 全棧行動派 (qzxdp.cn)
DatagramPacket
DatagramPacket
類用于表示一個數據包。它包含發送或接收的數據,以及目標或來源的IP地址和端口。
主要功能包括:
- 封裝數據(字節數組)。
- 存儲發送或接收數據包的目標或來源信息(IP地址和端口)。
主要方法
DatagramPacket(byte[] buf, int length)
: 創建用于接收數據的數據包。DatagramPacket(byte[] buf, int length, InetAddress address, int port)
: 創建用于發送數據的數據包。getData()
: 獲取數據包中的數據。getLength()
: 獲取數據包中數據的長度。getAddress()
: 獲取數據包的目標或來源地址。getPort()
: 獲取數據包的目標或來源端口。setData(byte[] buf)
: 設置數據包中的數據。setLength(int length)
: 設置數據包中數據的長度。setAddress(InetAddress address)
: 設置數據包的目標地址。setPort(int port)
: 設置數據包的目標端口。
筆者這里還是將官方的API文檔和對應的中文文檔給出:
DatagramPacket (Java SE 17 & JDK 17) (oracle.com)
DatagramPacket - Java17中文文檔 - API參考文檔 - 全棧行動派 (qzxdp.cn)
DatagramSocket
主要通過DatagramPacket
來傳輸和接收數據。在UDP通信中,DatagramPacket
用于封裝數據和相關信息(如目標地址和端口),而DatagramSocket
則用于實際的發送和接收操作。
舉個點外賣的例子來說明,假如今天是瘋狂星期四,小李想要點個肯德基的芝士漢堡,
DatagramSocket
就相對于是肯德基的大門以及小李家的大門,DatagramPacket
就相對于是外賣小哥,小李點的漢堡等食品就相對于是要傳輸的數據,當肯德基做好漢堡后,外賣小哥通過肯德基的大門的地址信息(DatagramSocket
)拿到漢堡(DatagramPacket
),然后由外賣小哥將食品包裝好,到小李家樓下后通過小李家的門牌號的信息(DatagramSocket
)找到小李,并且將漢堡交付給小李。
另外,這里對套接字需要簡單的做一個解釋:
套接字(Socket)是網絡通信的基本組件,它提供了一種機制,使得計算機能夠通過網絡進行數據傳輸。套接字是一個抽象概念,用于表示網絡通信的一個端點。無論是TCP還是UDP通信,套接字都是必不可少的。
UDP客戶端-服務端代碼實現
服務器端和客戶端在代碼實現方面是非常簡單的,在前文中有說到:UDP不是面向連接的而且協議本身就很簡單。因此在實現方面需要做的功能也很少,大致可以分為以下幾步:
- 創建套接字(DatagramSocket)。
- 發送(Send)和接收(Receive)數據包(DatagramPacket)。
- 關閉(Close)套接字。
?還是拿剛才買漢堡的例子,我們就可以這樣來實現:
UDP客戶端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Arrays;public class UDPClient {public static void main(String[] args) throws IOException {// 要發送的信息String messg = "我是小李,我想點一個芝士漢堡";// 建立SocketDatagramSocket socket = new DatagramSocket();// 建立收發容器byte[] sendData;byte[] receiveData = new byte[1024];// 發送數據包sendData = messg.getBytes();InetAddress serverAddress = InetAddress.getByName("localhost");DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverAddress, 9999);socket.send(sendPacket);// 接收數據包DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);socket.receive(receivePacket);String receivedMessage = new String(receivePacket.getData(), 0, receivePacket.getLength());System.out.println("Received from Server: " + receivedMessage);// 關閉套接字socket.close();}
}
UDP服務端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Arrays;public class UDPServer {public static void main(String[] args) throws IOException {// 要發送的信息String messg = "這里是肯德基,您的芝士漢堡已經制作完畢,祝您用餐愉快";// 建立SocketDatagramSocket socket = new DatagramSocket(9999);try {// 建立收發容器byte[] sendData;byte[] receiveData = new byte[1024];// 接收數據包DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);socket.receive(receivePacket);String receivedMessage = new String(receivePacket.getData(), 0, receivePacket.getLength());System.out.println("Received from Client: " + receivedMessage);// 發送數據包sendData = messg.getBytes();InetAddress clientAddress = receivePacket.getAddress();int clientPort = receivePacket.getPort();DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, clientAddress, clientPort);socket.send(sendPacket);} finally {// 關閉套接字if (socket != null && !socket.isClosed()) {socket.close();}}}
}
上述只是一個非常簡單的例子,實現了UDP通信中的一發一收的功能。要實現更豐富的功能也只需要稍微改一改就行,比如加上while循環就可以使得通信可以不間斷,一直發消息一直收消息,也可以加上文件讀寫的操作使得用戶的輸入可以更多樣化。
?本次的分享就到此為止了,希望我的分享能給您帶來幫助,創作不易也歡迎大家三連支持,你們的點贊就是博主更新最大的動力!
如有不同意見,歡迎評論區積極討論交流,讓我們一起學習進步!
有相關問題也可以私信博主,評論區和私信都會認真查看的,我們下次再見