Java使用DatagramSocket


轉自:http://book.51cto.com/art/201203/322540.htm

 

Java使用DatagramSocket代表UDP協議的Socket,DatagramSocket本身只是碼頭,不維護狀態,不能產生IO流,它的唯一作用就是接收和發送數據報,Java使用DatagramPacket來代表數據報,DatagramSocket接收和發送的數據都是通過DatagramPacket對象完成的。

先看一下DatagramSocket的構造器。

DatagramSocket():創建一個DatagramSocket實例,並將該對象綁定到本機默認IP地址、本機所有可用端口中隨機選擇的某個端口。

DatagramSocket(int prot):創建一個DatagramSocket實例,並將該對象綁定到本機默認IP地址、指定端口。

DatagramSocket(int port, InetAddress laddr):創建一個DatagramSocket實例,並將該對象綁定到指定IP地址、指定端口。

通過上面三個構造器中的任意一個構造器即可創建一個DatagramSocket實例,通常在創建服務器時,創建指定端口的DatagramSocket實例--這樣保證其他客戶端可以將數據發送到該服務器。一旦得到了DatagramSocket實例之后,就可以通過如下兩個方法來接收和發送數據。

receive(DatagramPacket p):從該DatagramSocket中接收數據報。

send(DatagramPacket p):以該DatagramSocket對象向外發送數據報。

從上面兩個方法可以看出,使用DatagramSocket發送數據報時,DatagramSocket並不知道將該數據報發送到哪里,而是由DatagramPacket自身決定數據報的目的地。就像碼頭並不知道每個集裝箱的目的地,碼頭只是將這些集裝箱發送出去,而集裝箱本身包含了該集裝箱的目的地。

下面看一下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地址和端口。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM