使用DatagramSocket發送、接收數據數組
Java使用DatagramSocket表明UDP協議的Socket,DatagramSocket自己只是碼頭,不維護狀態,不能產生IO 流,它的惟一做用就是接收和發送數據報,Java使用DatagramPacket來表明數據報,DatagramSocket接收和發送的數據都是經過 DatagramPacket對象完成的。服務器
先看一下DatagramSocket的構造器。socket
DatagramSocket():建立一個DatagramSocket實例,並將該對象綁定到本機默認IP地址、本機全部可用端口中隨機選擇的某個端口。spa
DatagramSocket(int prot):建立一個DatagramSocket實例,並將該對象綁定到本機默認IP地址、指定端口。線程
DatagramSocket(int port, InetAddress laddr):建立一個DatagramSocket實例,並將該對象綁定到指定IP地址、指定端口。設計
經過上面三個構造器中的任意一個構造器便可建立一個DatagramSocket實例,一般在建立服務器時,建立指定端口的 DatagramSocket實例--這樣保證其餘客戶端能夠將數據發送到該服務器。一旦獲得了DatagramSocket實例以後,就能夠經過以下兩 個方法來接收和發送數據。code
receive(DatagramPacket p):從該DatagramSocket中接收數據報。對象
send(DatagramPacket p):以該DatagramSocket對象向外發送數據報。開發
從上面兩個方法能夠看出,使用DatagramSocket發送數據報時,DatagramSocket並不知道將該數據報發送到哪裏,而是由 DatagramPacket自身決定數據報的目的地。就像碼頭並不知道每一個集裝箱的目的地,碼頭只是將這些集裝箱發送出去,而集裝箱自己包含了該集裝箱 的目的地。get
下面看一下DatagramPacket的構造器。
DatagramPacket(byte[] buf,int length):以一個空數組來建立DatagramPacket對象,該對象的做用是接收DatagramSocket中的數據。
DatagramPacket(byte[] buf, int length, InetAddress addr, int port):以一個包含數據的數組來建立DatagramPacket對象,建立該DatagramPacket對象時還指定了IP地址和端口--這就決 定了該數據報的目的地。
DatagramPacket(byte[] buf, int offset, int length):以一個空數組來建立DatagramPacket對象,並指定接收到的數據放入buf數組中時從offset開始,最多放length個字節。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):建立一個用於發送的DatagramPacket對象,指定發送buf數組中從offset開始,總共length個字節。
當Client/Server程序使用UDP協議時,實際上並無明顯的服務器端和客戶端,由於兩方都須要先創建一個DatagramSocket 對象,用來接收或發送數據報,而後使用DatagramPacket對象做爲傳輸數據的載體。一般固定IP地址、固定端口的DatagramSocket 對象所在的程序被稱爲服務器,由於該DatagramSocket能夠主動接收客戶端數據。
在接收數據以前,應該採用上面的第一個或第三個構造器生成一個DatagramPacket對象,給出接收數據的字節數組及其長度。而後調用 DatagramSocket 的receive()方法等待數據報的到來,receive()將一直等待(該方法會阻塞調用該方法的線程),直到收到一個數據報爲止。以下代碼所示:
// 建立一個接收數據的DatagramPacket對象 DatagramPacket packet=new DatagramPacket(buf, 256); // 接收數據報 socket.receive(packet);
在發送數據以前,調用第二個或第四個構造器建立DatagramPacket對象,此時的字節數組裏存放了想發送的數據。除此以外,還要給 出完整的目的地址,包括IP地址和端口號。發送數據是經過DatagramSocket的send()方法實現的,send()方法根據數據報的目的地址 來尋徑以傳送數據報。以下代碼所示:
// 建立一個發送數據的DatagramPacket對象 DatagramPacket packet = new DatagramPacket(buf, length, address, port); // 發送數據報 socket.send(packet);
使用DatagramPacket接收數據時,會感受DatagramPacket設計得過於煩瑣。開發者只關心該DatagramPacket能 放多少數據,而DatagramPacket是否採用字節數組來存儲數據徹底不想關心。但Java要求建立接收數據用的DatagramPacket時, 必須傳入一個空的字節數組,該數組的長度決定了該DatagramPacket能放多少數據,這實際上暴露了DatagramPacket的實現細節。接 着DatagramPacket又提供了一個getData()方法,該方法又能夠返回Datagram Packet對象裏封裝的字節數組,該方法更顯得有些多餘--若是程序須要獲取DatagramPacket裏封裝的字節數組,直接訪問傳給 DatagramPacket構造器的字節數組實參便可,無須調用該方法。
當服務器端(也能夠是客戶端)接收到一個DatagramPacket對象後,若是想向該數據報的發送者"反饋"一些信息,但因爲UDP協議是面向 非鏈接的,因此接收者並不知道每一個數據報由誰發送過來,但程序能夠調用DatagramPacket的以下3個方法來獲取發送者的IP地址和端口。
InetAddress getAddress():當程序準備發送此數據報時,該方法返回此數據報的目標機器的IP地址;當程序剛接收到一個數據報時,該方法返回該數據報的發送主機的IP地址。
int getPort():當程序準備發送此數據報時,該方法返回此數據報的目標機器的端口;當程序剛接收到一個數據報時,該方法返回該數據報的發送主機的端口。
SocketAddress getSocketAddress():當程序準備發送此數據報時,該方法返回此數據報的目標SocketAddress;當程序剛接收到一個數據報時,該方法返回該數據報的發送主機的SocketAddress。
getSocketAddress()方法的返回值是一個SocketAddress對象,該對象實際上就是一個IP地址和一個端口號。也就是 說,SocketAddress對象封裝了一個InetAddress對象和一個表明端口的整數,因此使用SocketAddress對象能夠同時表明 IP地址和端口。