UDP協議
在有些應用程序中,保持最快的速度比保證每一位數據都正確到達更重要。例如,在實時音頻或視頻中,丟失數據包只會作為干擾出現。干擾是可以容忍的,但當TCP請求重傳或等待數據包到達而它卻遲遲不到時,音頻流中就會出現尷尬的停頓,這讓人無法接受的。在其他應用中,可以在應用層實現可靠性傳輸。例如:如果客戶端向服務器發送一個短的UDP請求,倘若制定時間內沒有響應返回,它會認為這個包已丟失。域名系統就是采用這樣的工作方式。事實上,可以用UDP實現一個可靠的文件傳輸協議,而且很多人確實是這樣做的:網絡文件系統,簡單FTP都使用了UDP協議。在這些協議中由應用程序來負責可靠性。java中的UDP實現分為兩個類:DatagramPacket和 DatagramSocket。DatagramPacket類將數據字節填充到UDP包中,這稱為數據報。 DatagramSocket來發送這個包。要接受數據,可以從DatagramSocket中接受一個 DatagramPack對象,然后從該包中讀取數據的內容。
這種職責的划分與TCP使用的Socket和ServerSocket有所不同。首先,UDP沒有兩台主機間唯一連接的概念,它不需要知道對方是哪個遠程主機。它可以從一個端口往多個主機發送信息,但是TCP是無法做到的。其次,TCP socket把網絡鏈接看作是流:通過從Socket得到的輸入和輸出流來收發數據。UDP不支持這一點,你處理總是單個數據包。填充在一個數據報中的所有數據會以包的形式進行發送,這些數據要么作為一個組要么全部接收,要么全部丟棄。一個包不一定與下一個包相關。給定兩個包,沒有辦法知道哪個先發哪個后發。對於流來說,必須提供數據的有序隊列,與之不同,數據報會盡可能快的蜂擁到接收方。
一個UDP客戶端
package com.dy.xidian;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class DaytimeUDPClient {
private final static int PORT = 13;
private static final String HOSTNAME = "www.xdysite.cn";
public static void main(String[] args) {
//傳入0表示讓操作系統分配一個端口號
try (DatagramSocket socket = new DatagramSocket(0)) {
socket.setSoTimeout(10000);
InetAddress host = InetAddress.getByName(HOSTNAME);
//指定包要發送的目的地
DatagramPacket request = new DatagramPacket(new byte[1], 1, host, PORT);
//為接受的數據包創建空間
DatagramPacket response = new DatagramPacket(new byte[1024], 1024);
socket.send(request);
socket.receive(response);
String result = new String(response.getData(), 0, response.getLength(), "ASCII");
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
}
}
一個UDP服務器
package com.dy.xidian;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Date;
public class DaytimeUDPServer {
private final static int PORT = 13;
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket(PORT)) {
while (true) {
try {
DatagramPacket request = new DatagramPacket(new byte[1024], 1024);
socket.receive(request);
String daytime = new Date().toString();
byte[] data = daytime.getBytes("ASCII");
DatagramPacket response = new DatagramPacket(data, data.length, request.getAddress(), request.getPort());
socket.send(response);
System.out.println(daytime + " " + request.getAddress());
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}