1 DatagramSocket 類
要收發DatagramPacket必須打開一個數據報socket ,當服務器構造DatagramSocket時。
1.1 服務器和客戶端的服務器
兩者使用的socket都是一樣的,區別僅僅在於 服務器端的端口是已知端口,而客戶端的端口是系統分配的。
TCP端口和UDP端口之間沒有關聯,所以兩者可以共同綁定在同一個端口上,而不會有相互影響。
1.2 DatagramSocket 類的構造函數
DatagramSocket創建一個在指定端口監聽的入站數據報的 socket ,使用此構造函數可以編寫出在指導的端口監聽的服務器。
如果服務器在匿名端口監聽,客戶端就無法與之聯繫。
DatagramSocket 中的receive 方法,是阻塞方法,只有當接收到數據的時候,纔會進行下面的代碼,否則只會阻塞當前的進程。
1.3 一個簡單的UDP 客戶端
客戶端接收用戶在控制檯上的輸入,然後調用 DatagramSocket 中的send方法, 將數據傳遞出去。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class UDPDiscardClient extends Thread {
public final static int DEFAULT_PORT = 3000;
public UDPDiscardClient() {
start();
}
public void run() {
String hostname = "localhost";
int port = DEFAULT_PORT;
try {
InetAddress server = InetAddress.getByName(hostname);
BufferedReader userInput = new BufferedReader(
new InputStreamReader(System.in));
DatagramSocket theSocket = new DatagramSocket();
while (true) {
String theLine = userInput.readLine();
if (theLine.equals("."))
break;
byte[] data = theLine.getBytes("UTF-8");
DatagramPacket theOutput = new DatagramPacket(data,
data.length, server, port);
theSocket.send(theOutput);
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
new UDPDiscardClient();
}
}
1.4 UDP服務器
每當接收到一個數據報的時候,packet需要設置成最大的可能的值,否則當接收多個數據報以後,packet的值會變成已經接收到的最小的值。
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UDPDiscardServer extends Thread { public final static int DEFAULT_PORT = 3000; public final static int MAX_PACKET_SIZE = 65507; public UDPDiscardServer() { start(); } public void run() { serverWork(); } public void serverWork() { int port = DEFAULT_PORT; byte[] buffer = new byte[MAX_PACKET_SIZE]; // port = Integer.parseInt(args[0]); try { DatagramSocket server = new DatagramSocket(port); DatagramPacket packet = new DatagramPacket(buffer, buffer.length); while (true) { server.receive(packet); String s = new String(packet.getData(), 0, packet.getLength(), "UTF-8"); System.out.println("我是服務器:" + packet.getAddress() + "at port " + packet.getPort() + "says" + s); /**//* 必須重新設置 */ packet.setLength(buffer.length); } } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { new UDPDiscardServer(); } } |
2 感想
利用UDP協議來收發數據,都是將數據放在DatagramPacket 中,而TCP協議都是放在流中,通過getInputStream 和 getOutputStream 函數來獲得流。
在服務器端UDP需要調用含有端口參數的DatagramSocket 構造函數 , 在客戶端設置DatagramSocket時,調用匿名端口構造函數。
然後在構造DatagramPacket 構造函數的時候,發送端需要制定發送主機的 主機名 和 端口 。