Java網絡編程:UDP DatagramSocket
DatagramSocket類是java通過UDP通信的途徑。UDP仍位於IP層的上麵。 你可以用DatagramSocket類發送和接收UDP數據包。
UDP 和TCP
UDP工作方式和TCP有點不同。當你通過TCP發送數據時,你先要創建連接。一旦TCP連接建立了,TCP會保證你的數據傳遞到對端,否則它將告訴你已發生的錯誤。
僅僅用UDP來發送數據包(datagrams)到網絡間的某個IP地址。你不能保證數據會不會到達。你也不能保證UDP數據包到達接收方的指令。這意味著UDP比TCP有更少的協議開銷(無完整檢查流)。
當數據傳輸過程中不在乎數據包是否丟失時,UDP就比較適合這樣的數據傳輸。比如,網上的電視信號的傳輸。你希望信號到達客戶端時盡可能地接近直播。因此,如果丟失一兩個畫麵,你一點都不在乎。你不希望直播延遲,值想確保所有的畫麵顯示在客戶端。你寧可跳過丟失的畫麵,希望一直看到最新的畫麵。
這種情況也會發生在網上攝像機直播節目中。誰會關心過去發生的什麼,你隻想顯示當前的畫麵。你不希望比實際情況慢30s結束,隻因為你想看到攝像機顯示給觀眾的所有畫麵。這跟攝像機錄像有點不同。從攝像機錄製畫麵到磁盤,你不希望丟失一個畫麵。你可能還希望有點延遲,如果有重大的情況發生,就不需要倒回去檢查畫麵。
通過DatagramSocket發送數據
通過Java的DatagramSocket類發送數據,首先需要創建DatagramPacket。如下:
1 |
buffer = new byte [ 65508 ];
|
2 |
3 |
InetAddress address = new DatagramPacket(buffer, buffer.length, address, 9000 );
|
字節緩衝塊(字節數組)就是UDP數據包中用來發送的數據。緩衝塊上限長度為65508字節,是單一UDP數據包發送的最大的數據量。
數據包構造函數的長度就是緩存塊中用於發送的數據的長度。所有多於最大容量的數據都會被忽略。
包含節點(例如服務器)地址的InetAddress實例攜帶節點(如服務器)的地址發送的UDP數據包。InetAddress類表示一個ip地址(網絡地址)。getByName()方法返回帶有一個InetAddress實例,該實例帶有匹配主機名的ip地址。
端口參數是UDP端口服務器用來接收正在監聽的數據。UDP端口和TCP端口是不一樣的。一台電腦同時有不同的進程監聽UDP和TCP 80端口。
為了發送數據包,你需要創建DatagramSocket來發送數據。如下:
1 |
DatagramSocketdatagramSocket = new DatagramSocket();
|
調用send()方法發送數據,像這樣:
1 |
datagramSocket.send(packet); |
完整示例:
1 |
DatagramSocketdatagramSocket = new DatagramSocket();
|
2 |
3 |
byte [] buffer = "0123456789" .getBytes();
|
4 |
5 |
InetAddressreceiverAddress = InetAddress.getLocalHost(); |
6 |
7 |
DataframPacket packet = new DatagramPacket( buffer, buffer.length, receiverAddress, 80 );
|
8 |
datagramSocket.send(packet); |
從DatagramSocket獲取數據
從DataframSocket獲取數據時,首先創建DataframPacket ,然後通過DatagramSocket類的receive()方法接收數據。例如:
1 |
DatagramSocketdatagramSocket = new DatagramSocket( 80 );
|
2 |
3 |
byte [] buffer = new byte [ 10 ];
|
4 |
5 |
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
6 |
7 |
datagramSocket.receive(packet); |
注意DatagramSocket是如何通過傳遞參數80到它的構造器初始化的。這個參數是UDP端口的DatagramSocket用來接收UDP數據包的。像之前提到的,TCP和UDP端口是不一樣的,也不重疊。你可以有倆個不同的進程同時在端口80監聽TCP和UDP,沒有任何衝突。
第二,字節緩存塊和DatagramPacket創建了。注意DatagramPacket是沒有關於節點如何發送數據的信息的,當創建一個方數據的DatagramPacket時,它會直到這個信息。這就是為什麼我們會用DatagramPacket接收數據而不是發送數據。因此沒有目標地址是必須的。
最後,調用DatagramSocket的receive()方法。直到數據包接收到為止,這個方法都是阻塞的。
接收的數據位於DatagramPacket的字節緩衝塊。緩衝塊可以通過調用getData()獲得:
1 |
byte [] buffer = packet.getData();
|
緩衝塊接收了多少的數據需要你去找出來。你用的協議應該定義每個UDP包發多少數據,活著定義一個你能找到的數據結束標記。
一個真正的服務端程序可能會在一個loop中調用receive()方法,傳送所有接收到的DatagramPacket到工作的線程池中,就像TCP服務器處理請求連接一樣(查看Java Multithreaded Servers獲取更多詳情)
最後更新:2017-05-19 17:01:55