| 1 UDP套接字?
數(shù)據(jù)報(bào)(Datagram)是網(wǎng)絡(luò)層數(shù)據(jù)單元在介質(zhì)上傳輸信息的一種邏輯分組格式,它是一種在網(wǎng)絡(luò)中傳播的、獨(dú)立的、自身包含地址信息的消息,它能否到達(dá)目的地、到達(dá)的時(shí)間、到達(dá)時(shí)內(nèi)容是否會(huì)變化不能準(zhǔn)確地知道。它的通信雙方是不需要建立連接的,對(duì)于一些不需要很高質(zhì)量的應(yīng)用程序來(lái)說(shuō),數(shù)據(jù)報(bào)通信是一個(gè)非常好的選擇。還有就是對(duì)實(shí)時(shí)性要求很高的情況,比如在實(shí)時(shí)音頻和視頻應(yīng)用中,數(shù)據(jù)包的丟失和位置錯(cuò)亂是靜態(tài)的,是可以被人們所忍受的,但是如果在數(shù)據(jù)包位置錯(cuò)亂或丟失時(shí)要求數(shù)據(jù)包重傳,就是用戶所不能忍受的,這時(shí)就可以利用UDP協(xié)議傳輸數(shù)據(jù)包。在Java的java.net包中有兩個(gè)類DatagramSocket和DatagramPacket,為應(yīng)用程序中采用數(shù)據(jù)報(bào)通信方式進(jìn)行網(wǎng)絡(luò)通信。?
使用數(shù)據(jù)包方式首先將數(shù)據(jù)打包,Java.net包中的DategramPacket類用來(lái)創(chuàng)建數(shù)據(jù)包。 數(shù)據(jù)包有, 一種用來(lái),該數(shù)據(jù)包有要傳遞到的目的地址; 另一種數(shù)據(jù)包用來(lái)接收傳遞過(guò)來(lái)的數(shù)據(jù)包中的數(shù)據(jù)。要?jiǎng)?chuàng)建,通過(guò)DatagramPackett類的方法構(gòu)造: public DatagramPacket(byte ibuft[],int ilength) 傳遞數(shù)據(jù)包 public DatagramPacket( byte ibuft[],int ,int ilength) 接收數(shù)據(jù)包
ibuf[]為接受數(shù)據(jù)包的存儲(chǔ)數(shù)據(jù)的緩沖區(qū)的長(zhǎng)度,ilength為從傳遞過(guò)來(lái)的數(shù)據(jù)包中讀取的字節(jié)數(shù)。當(dāng)采用第一種構(gòu)造方法時(shí),接收到的數(shù)據(jù)從ibuft[0]開(kāi)始存放,直到整個(gè)數(shù)據(jù)包接收完畢或者將ilength的字節(jié)寫(xiě)入ibuft為止。采用第二種構(gòu)造方法時(shí),接收到的數(shù)據(jù)從ibuft[offset]開(kāi)始存放。。不過(guò)這是RuntimeException,不需要用戶代碼捕獲。示范代碼如下: byte[ ] buffer=new byte[8912]; DatagramPacket datap=new DatagramPacket(buffer ,buffer.length( ));?
創(chuàng)建的構(gòu)造方法為: public DatagramPacket(byt ibuf[],int ilength,InetAddrss iaddr,int port) public DatagramPacket(byt ibuf[],int offset , int ilength,InetAddrss iaddr,int port)?
iaddr為數(shù)據(jù)包要傳遞到的目標(biāo)地址,port為目標(biāo)地址的程序接受數(shù)據(jù)包的端口號(hào)(即目標(biāo)地址的計(jì)算機(jī)上運(yùn)行的客戶程序是在哪一個(gè)端口接收服務(wù)器發(fā)送過(guò)來(lái)的數(shù)據(jù)包)。ibuf[]為要發(fā)送數(shù)據(jù)的存儲(chǔ)區(qū),以ibuf數(shù)組的offset位置開(kāi)始填充數(shù)據(jù)包ilength字節(jié),如果沒(méi)有offset,則從ibuf數(shù)組的0位置開(kāi)始填充。以下示范代碼是要發(fā)送一串字符串:?
String s = new String("java networking"); byte[ ] data=s.getbytes(); int port=1024; try{ InetAddress ineta= InetAddress.getByName(" 169.254.0.14"); DatagramPacket datap=new DatagramPacket (data ,data.length( ),ineta,port); } catch(IOException e) { }
數(shù)據(jù)包也是對(duì)象,也有操作方法用來(lái),這是很有用的。其方法如下:
public InetAddress getAddress() 如果是發(fā)送數(shù)據(jù)包,則獲得數(shù)據(jù)包要發(fā)送的目標(biāo)地址,但是如果是接收數(shù)據(jù)包則返回發(fā)送此數(shù)據(jù)包的。
public byte[]getData()?
返回一個(gè)字節(jié)數(shù)組,其中是數(shù)據(jù)包的數(shù)據(jù)。如果想把字節(jié)數(shù)組轉(zhuǎn)換成別的類型就要進(jìn)行轉(zhuǎn)化。如果想轉(zhuǎn)化成String類型,可以進(jìn)行以下的處理,設(shè)DatagramPacket datap為: String s = new String(datap.getbytes());?
public int getLength() 獲得數(shù)據(jù)包中數(shù)據(jù)的字節(jié)數(shù)。
pubic int getPort( ) 返回?cái)?shù)據(jù)包中的。?
發(fā)送和接收數(shù)據(jù)包還需要發(fā)送和接收數(shù)據(jù)包的,即DatagramSocket對(duì)象,DatagramSocket套接字在本地機(jī)器端口監(jiān)聽(tīng)是否有數(shù)據(jù)到達(dá)或者將數(shù)據(jù)包發(fā)送出去。其構(gòu)造方法如下。?
public DatagramSocket() 用本地機(jī)上任何一個(gè)可用的端口創(chuàng)建一個(gè)套接字,這個(gè)端口號(hào)是由系統(tǒng)隨機(jī)產(chǎn)生的。使用方法如下:?
try{ DatagramSocket datas=new DatagramSocket( ); //發(fā)送數(shù)據(jù)包 } catch(SocketException e){ }
這種構(gòu)造方法沒(méi)有指定端口號(hào),可以用在客戶端。如果構(gòu)造不成功則觸發(fā)SocketException異常。
public DatagramSocket(int port)? 用一個(gè)指定的端口號(hào)port創(chuàng)建一個(gè)套接字。?
當(dāng)不能創(chuàng)建套接字時(shí)就拋出SocketException異常,其原因是指定的或者是試圖的端口,但是又沒(méi)有。?
2 實(shí)例:利用DatagramSocket查詢端口占用情況?
我們可以利用這個(gè)異常探查本地機(jī)的端口號(hào)有沒(méi)有服務(wù)。見(jiàn)示例12-9。 【程序源代碼】?
1 // ==================== Program Description ===================== 2 // 程序名稱:示例12-9: UDPScan.java 3 // 程序目的:熟悉DatagramSocket的基本用法,查詢端口的占用情況 4 //========================================================= 5 import java.net.*; 6? 7 public class UDPScan 8 { 9 public static void main(String args[]) 10 { 11 for (int port=1024;port<=65535;port++) { 12 try { 13 DatagramSocket server=new DatagramSocket(port); 14 server.close(); 15 } 16 catch(SocketException e) { 17 System.out.println("there is a server in port "+port+"."); 18 } 19 } 20 } 21 }
【程序輸出結(jié)果】?
there is a server in port 1026. there is a server in port 1028. there is a server in port 1046. there is a server in port 1900.
【程序注解】 在第11~19行我們用for循環(huán)以端口號(hào)為參數(shù)實(shí)例化DatagramSocket,其中端口號(hào)從1024到65535。如果在實(shí)例過(guò)程中出錯(cuò),會(huì)拋出SocketException異常。我們根據(jù)這個(gè)異常就可以判斷出哪些端口被占用,哪些還是空閑的。值得一提的是,我們?cè)趯?shí)例化了DatagramSocket后,調(diào)用了close()關(guān)閉它。作為一種好的作風(fēng),應(yīng)該遵循。端口號(hào)在1024以下的系統(tǒng)可能會(huì)用到,比如HTTP默認(rèn)為80端口,FTP默認(rèn)為21端口,等等,所以我們從1024端口開(kāi)始探查。?
套接字對(duì)象也有相應(yīng)的方法,例如發(fā)送數(shù)據(jù)包的方法還有接收數(shù)據(jù)包的方法,介紹如下。
pubic void close() 當(dāng)我們創(chuàng)建一個(gè)套接字后,用該方法關(guān)閉套接字。
public int getLocalPort() 返回本地套接字的正在監(jiān)聽(tīng)的端口號(hào)。
public void receive(DatagramPacket p) 從網(wǎng)絡(luò)上接收數(shù)據(jù)包并將其存儲(chǔ)在DatagramPacket對(duì)象p中。p中的數(shù)據(jù)緩沖區(qū)必須足夠大,。接收數(shù)據(jù)出錯(cuò)時(shí)會(huì)拋出IOException異常。
public Void Send(DatagramPacket p) 發(fā)送數(shù)據(jù)包,出錯(cuò)時(shí)會(huì)發(fā)生IOException異常。?
下面,我們?cè)敿?xì)解釋在Java中實(shí)現(xiàn)客戶端與服務(wù)器之間數(shù)據(jù)報(bào)通信的方法。 應(yīng)用程序的工作流程如下:?
(1)首先要建立數(shù)據(jù)報(bào)通信的Socket,我們可以通過(guò)創(chuàng)建一個(gè)DatagramSocket對(duì)象實(shí)現(xiàn)它,在Java中DatagramSocket類有如下兩種構(gòu)造方法:
public DatagramSocket() 構(gòu)造一個(gè)數(shù)據(jù)報(bào)socket,并使其與本地主機(jī)任一可用的端口連接。若打不開(kāi)socket則拋出SocketException異常。
public DatagramSocket(int port) 構(gòu)造一個(gè)數(shù)據(jù)報(bào)socket,并使其與本地主機(jī)指定的端口連接。若打不開(kāi)socket或socket無(wú)法與指定的端口連接則拋出SocketException異常。?
(2)創(chuàng)建一個(gè)數(shù)據(jù)報(bào)文包,用來(lái)實(shí)現(xiàn)無(wú)連接的包傳送服務(wù)。每個(gè)數(shù)據(jù)報(bào)文包用DatagramPacket類創(chuàng)建,DatagramPacket對(duì)象封裝了數(shù)據(jù)報(bào)包數(shù)據(jù)、包長(zhǎng)度、目標(biāo)地址和目標(biāo)端口。客戶端要發(fā)送數(shù)據(jù)報(bào)文包,要調(diào)用DatagramPacket類以如下形式的構(gòu)造函數(shù)創(chuàng)建DatagramPacket對(duì)象,將要發(fā)送的數(shù)據(jù)和包文目的地址信息放入對(duì)象之中。DatagramPacket(byte bufferedarray[],int length,InetAddress address,int port)即構(gòu)造一個(gè)包長(zhǎng)度為length的包傳送到指定主機(jī)指定端口號(hào)上的數(shù)據(jù)報(bào)文包,參數(shù)length必須小于等于bufferedarry.length。?
DatagramPacket類提供了4個(gè)類獲取信息:
public byte[] getData() 返回一個(gè)字節(jié)數(shù)組,包含收到或要發(fā)送的數(shù)據(jù)報(bào)中的數(shù)據(jù)。
public int getLength() 返回發(fā)送或接收到的數(shù)據(jù)的長(zhǎng)度。
public InetAddress getAddress() 返回一個(gè)發(fā)送或接收此數(shù)據(jù)報(bào)包文的機(jī)器的IP地址。?
public int getPort() 返回發(fā)送或接收數(shù)據(jù)報(bào)的遠(yuǎn)程主機(jī)的端口號(hào)。?
(3)創(chuàng)建完DatagramSocket和DatagramPacket對(duì)象,就可以發(fā)送數(shù)據(jù)報(bào)文包了。發(fā)送是通過(guò)調(diào)用,它需要以DatagramPacket對(duì)象為參數(shù),將剛才封裝進(jìn)DatagramPacket對(duì)象中的數(shù)據(jù)組成數(shù)據(jù)報(bào)發(fā)出。?
(4)當(dāng)然,我們也可以接收數(shù)據(jù)報(bào)文包。為了接收從服務(wù)器返回的結(jié)果數(shù)據(jù)報(bào)文包,我們需要?jiǎng)?chuàng)建一個(gè)新的DatagramPacket對(duì)象,這就需要用到DatagramPacket的另一種構(gòu)造方式DatagramPacket(byte bufferedarray[],int length),即只需指明存放接收的數(shù)據(jù)報(bào)的緩沖區(qū)和長(zhǎng)度。調(diào)用DatagramSocket對(duì)象的報(bào)的工作,此時(shí)需要將上面創(chuàng)建的DatagramPacket對(duì)象作為參數(shù),該方法會(huì)一直直到收到一個(gè)數(shù)據(jù)報(bào)文包,此時(shí)DatagramPacket的緩沖區(qū)中包含的就是接收到的數(shù)據(jù),數(shù)據(jù)報(bào)文包中也包含發(fā)送者的IP地址,發(fā)送者機(jī)器上的端口號(hào)等信息。?
(5)處理接收緩沖區(qū)內(nèi)的數(shù)據(jù),獲取服務(wù)結(jié)果。?
(6)當(dāng)通信完成后,可以使用DatagramSocket對(duì)象的close()方法關(guān)閉數(shù)據(jù)報(bào)通信Socket。當(dāng)然,Java會(huì)自動(dòng)關(guān)閉Socket,DatagramSocket和DatagramPacket所占用的。但是作為一種良好的編程習(xí)慣,。?
3 實(shí)例:利用數(shù)據(jù)報(bào)通信的C/S程序 示例12-10給出了一個(gè)簡(jiǎn)單的利用數(shù)據(jù)報(bào)通信的客戶端程序,它能夠完成與服務(wù)器簡(jiǎn)單的通信。 【程序源代碼】?
1 // ==================== Program Description =================== 2 // 程序名稱:示例12-10: UDPServer.java 3 // 程序目的:創(chuàng)建UDP服務(wù)器 4 //============================================================= 5 import java.net.*; 6 import java.io.*; 7? 8 public class UDPServer 9 { 10 static public void main(String args[]) 11 { 12 try {? 13 DatagramSocket receiveSocket = new DatagramSocket(5000); 14 byte buf[]=new byte[1000]; 15 DatagramPacket receivePacket=new DatagramPacket(buf,buf.length); 16 System.out.println("startinig to receive packet"); 17 while (true) 18 {? 19 receiveSocket.receive(receivePacket); 20 String name=receivePacket.getAddress().toString(); 21 System.out.println("\n來(lái)自主機(jī):"+name+"\n端口:" 22 +receivePacket.getPort()); 23 String s=new String(receivePacket.getData(),0,receivePacket.getLength()); 24 System.out.println("the received data: "+s); 25 } 26 } 27 catch (SocketException e) { 28 e.printStackTrace(); 29 System.exit(1); 30 } 31 catch(IOException e) { 32 System.out.println("網(wǎng)絡(luò)通信出現(xiàn)錯(cuò)誤,問(wèn)題在"+e.toString()); 33 } 34 } 35 }
【程序輸出結(jié)果】?
startinig to receive packet 來(lái)自主機(jī):/166.111.172.20 端口:3456 the received data: hello! this is the client
【程序注解】 第13行和第15行分別實(shí)例化了一個(gè)DatagramSocket對(duì)象receiveSocket和一個(gè)DatagramPacket對(duì)象receivePacket,都是通過(guò)調(diào)用各自的構(gòu)造函數(shù)實(shí)現(xiàn)的,為建立服務(wù)器做好準(zhǔn)備。在while這個(gè)永久循環(huán)中,receiveSocket這個(gè)套接字始終嘗試receive()方法接收DatagramPacket數(shù)據(jù)包,當(dāng)接收到數(shù)據(jù)包后,就調(diào)用DatagramPacket的一些成員方法顯示一些數(shù)據(jù)包的信息。在程序中調(diào)用了getAddress()獲得地址,getPort()方法獲得客戶端套接字的端口,getData()獲得客戶端傳輸?shù)臄?shù)據(jù)。注意getData( )返回的是字節(jié)數(shù)組,我們把它轉(zhuǎn)化為字符串顯示。在第27~33行我們對(duì)程序中發(fā)生的SocketException和IOException異常進(jìn)行了處理。 示例12-11是UDP客戶端的程序。 【程序源代碼】?
1 // ==================== Program Description =================== 2 // 程序名稱:示例12-11: UDPClient.java 3 // 程序目的:創(chuàng)建UDP客戶端 4 //============================================================= 5 import java.net.*; 6 import java.io.*; 7? 8 public class UDPClient 9 { 10 public static void main(String args[]) 11 { 12 try { 13 DatagramSocket sendSocket=new DatagramSocket(3456); 14 String string="asfdfdfggf"; 15 byte[] databyte=new byte[100]; 16 databyte=string.getBytes(); 17 DatagramPacketsendPacket=new DatagramPacket(databyte,string.length(),? 18 InetAddress.getByName("163.121.139.20"), 5000);? 19 sendSocket.send(sendPacket); 20 System.out.println("send the data: hello ! this is the client"); 21 } 22 catch (SocketException e) { 23 System.out.println("不能打開(kāi)數(shù)據(jù)報(bào)Socket,或數(shù)據(jù)報(bào)Socket無(wú)法與指定 24 端口連接!"); 25 } 26 catch(IOException ioe) { 27 System.out.println("網(wǎng)絡(luò)通信出現(xiàn)錯(cuò)誤,問(wèn)題在"+ioe.toString()); 28 }? 29 } 30 }
【程序輸出結(jié)果】 send the data: hello !this is the clientsend the data: hello !this is the client?
【程序注解】 第13行用DatagramSocket的構(gòu)造函數(shù)實(shí)例化一個(gè)發(fā)送數(shù)據(jù)的套接字sendSocket。第17~18行實(shí)例化了一個(gè)DatagramPacket,其中數(shù)據(jù)包要發(fā)往的目的地是163.121.139.20,端口是5000。當(dāng)構(gòu)造完數(shù)據(jù)包后,就調(diào)用send( )方法將數(shù)據(jù)包發(fā)送出去。?
4 組播套接字?
在Java中,可以用java.net.MulticastSocket類組播數(shù)據(jù)。組播套接字是DatagramSocket的子類,定義如下: public class MulticastSocket extends DatagramSocket?
構(gòu)造方法有兩個(gè): public MulticastSocket ( ) throws SocketException public MulticastSocket (int port ) throws SocketException?
以上兩個(gè)方法都是創(chuàng)建組播套接字,第一個(gè)方法沒(méi)有端口號(hào),第二個(gè)指定了端口號(hào)。 常用的方法如下:
public void joinGroup(InetAddress address) throws IOException?
建立了MulticastSocket對(duì)象后,為了發(fā)送或者接收組播包,必須用joinGroup方法加入一個(gè)組播組。若加入的不是組播地址將觸發(fā)IOException異常。
public void leaveGroup(InetAddress address)throws IOException?
如果不想接收組播包了,就調(diào)用leaveGroup方法。程序就發(fā)信息到組播路由器,通知它向此用戶發(fā)送數(shù)據(jù)。若想離開(kāi)的地址不是組播地址就觸發(fā)IOException異常。
public void send(DatagramPacket packet, byte, ttl) throws IOExceptin 發(fā)送組播包的方法與DatagramSocket發(fā)送數(shù)據(jù)相似。其中ttl是生存時(shí)間,大小在0~255之間。
public void receive(DatagramPacket p) 與DatagramSocket的接收方法沒(méi)有差別。
public void setTimeToLive(int ttl )throws IOException 設(shè)置套接字發(fā)出的組播包中的默認(rèn)ttl數(shù)值。
public int getTimeToLive( ) throws IOException 返回ttl數(shù)值。?
使用組播套接字發(fā)送數(shù)據(jù)的過(guò)程是首先用MulticastSocket()構(gòu)造器創(chuàng)建MulticastSocket類,然后利用MulticastSocket類的joinGroup()方法加入一個(gè)組播組,之后創(chuàng)建DatagramPacket數(shù)據(jù)包,最后調(diào)用MulticastSocket類的send()方法發(fā)送組播包。 發(fā)送組播包的代碼如下:?
try { InetAddress address = InetAddress.getByName (www.mmm.net) ; byte[ ] data=" java networking"; int port =5000; DatagramPacket datap =new DatagramSocket? (data ,data.length( ),address,port); MulticastSocket muls =new MulticastSocket ( ); muls.send(datap ); } catch(IOException ie) {? }
使用組播套接字接收數(shù)據(jù)的過(guò)程是首先用MulticastSocket()構(gòu)造器創(chuàng)建MulticastSocket類,然后利用MulticastSocket類的joinGroup()方法加入一個(gè)組播組,之后用receive()方法接收組播包。我們發(fā)現(xiàn)其過(guò)程與UDP包的過(guò)程很相似,區(qū)別是要加入一個(gè)組播組。?
5 實(shí)例:組播套接字C/S程序?
下面的程序示例12-12說(shuō)明了組播套接字的基本用法。 【程序源代碼】?
1 // ==================== Program Description =====================? 2 // 程序名稱:示例12-12: MulticastServer.java 3 // 程序目的:創(chuàng)建一個(gè)組播服務(wù)器 4 //========================================================== 5 import java.io.*; 6 import java.net.*; 7 import java.util.*; 8? 9 class QuoteServerThread extends Thread? 10 { 11 protected DatagramSocket socket = null; 12 protected BufferedReader in = null; 13 protected boolean moreQuotes = true; 14? 15 public QuoteServerThread() throws IOException { 16 this("QuoteServerThread"); 17 } 18? 19 public QuoteServerThread(String name) throws IOException { 20 super(name); 21 socket = new DatagramSocket(4445); 22? 23 try { 24 in = new BufferedReader(new FileReader("one-liners.txt")); 25 } catch (FileNotFoundException e) { 26 System.err.println("Could not open quote file.? Serving time instead."); 27 } 28 } 29? 30 public void run() { 31 while (moreQuotes) { 32 try { 33 byte[] buf = new byte[256]; 34? 35 // 獲取請(qǐng)求 36 DatagramPacket packet = new DatagramPacket(buf, buf.length); 37 socket.receive(packet); 38? 39 // 進(jìn)行響應(yīng) 40 String dString = null; 41 if (in == null) 42 dString = new Date().toString(); 43 else 44 dString = getNextQuote(); 45 buf = dString.getBytes(); 46? 47 // 向用戶發(fā)送響應(yīng) 48 InetAddress address = packet.getAddress(); 49 int port = packet.getPort(); 50 packet = new DatagramPacket(buf, buf.length, address, port); 51 socket.send(packet); 52 } 53 catch (IOException e) { 54 e.printStackTrace(); 55 moreQuotes = false; 56 } 57 } 58 socket.close(); 59 } 60? 61 protected String getNextQuote() { 62 String returnValue = null; 63 try { 64 if ((returnValue = in.readLine()) == null) { 65 in.close(); 66 moreQuotes = false; 67 returnValue = "No more quotes. Goodbye."; 68 } 69 } catch (IOException e) { 70 returnValue = "IOException occurred in server."; 71 } 72 return returnValue; 73 } 74 } 75? 76 class MulticastServerThread extends QuoteServerThread? 77 { 78 private long FIVE_SECONDS = 5000; 79? 80 public MulticastServerThread() throws IOException { 81 super("MulticastServerThread"); 82 } 83? 84 public void run() { 85 while (moreQuotes) { 86 try { 87 byte[] buf = new byte[256]; 88? 89 // 構(gòu)造引用 90 String dString = null; 91 if (in == null) 92 dString = new Date().toString(); 93 else 94 dString = getNextQuote(); 95 buf = dString.getBytes(); 96? 97 // 發(fā)送 98 InetAddress group = InetAddress.getByName("136.122.133.1"); 99 DatagramPacket packet =new DatagramPacket(buf,buf.length,group,? 100 4446); 101 socket.send(packet); 102? 103 // 休眠 104 try { 105 sleep((long)(Math.random() * FIVE_SECONDS)); 106 }? 107 catch (InterruptedException e) { } 108 }? 109 catch (IOException e) { 110 e.printStackTrace(); 111 moreQuotes = false; 112 } 113 } 114 socket.close(); 115 } 116 } 117? 118 public class MulticastServer { 119 public static void main(String[] args) throws java.io.IOException { 120 new MulticastServerThread().start(); 121 } 122 }
【程序注解】 服務(wù)器程序由3個(gè)類組成:QuoteServerThread,MulticastServerThread和MulticastServer。它們的關(guān)系是:QuoteServerThread繼承自線程類,而MulticastServerThread類繼承自類QuoteServerThread。這個(gè)程序主要的部分在QuoteServerThread和MulticastServerThread。QuoteServerThread類有兩個(gè)構(gòu)造函數(shù),其中在構(gòu)造函數(shù)QuoteServerThread(String name)中,初始化了DatagramSocket套接字并打開(kāi)了文件one-liners.txt,在這個(gè)文件中存有服務(wù)器發(fā)送的字符串。?
在QuoteServerThread類的run()函數(shù)中,服務(wù)器端套接字接收來(lái)自客戶端的數(shù)據(jù)包,并從文件中讀取數(shù)據(jù),把信息發(fā)給客戶端。?
MulticastServerThread類中重載了run( )方法,實(shí)現(xiàn)的功能基本相同,在發(fā)完服務(wù)器的信息后,用sleep( )函數(shù)停止處理了一個(gè)隨機(jī)的時(shí)間。?
在MultiServer類中,用 new MulticastServerThread().start()開(kāi)始服務(wù)器線程。我們現(xiàn)在只是關(guān)注其基本思想。?
示例12-13是UDP組播的客戶端程序。 【程序源代碼】?
1 // ==================== Program Description =====================? 2 // 程序名稱:示例12-13: MulticastClient.java 3 // 程序目的:UDP組播客戶端 4 //====================>7��:示例1D==================================== 5 import java.io.*; 6 import java.net.*; 7 import java.util.*; 8? 9 public class MulticastClient? 10 { 11 public static void main(String[] args) throws IOException? 12 { 13 MulticastSocket socket = new MulticastSocket(4446); 14 InetAddress address = InetAddress.getByName("136.122.133.1"); 15 socket.joinGroup(address); 16 DatagramPacket packet; 17? 18 for (int i = 0; i < 5; i++)? 19 { 20 byte[] buf = new byte[256]; 21 packet = new DatagramPacket(buf, buf.length); 22 socket.receive(packet); 23 String received = new String(packet.getData()); 24 System.out.println("Quote of the Moment: " + received); 25 } 26? 27 socket.leaveGroup(address); 28 socket.close(); 29 } 30 }
【程序輸出結(jié)果】?
Quote of the Moment: Give me ambiguity or give me something else. Quote of the ME7��:示例1oment: I.R.S.: We've got what it takes to take what you've got! Quote of the Moment: We are born naked, wet and hungry. Then things get worse. Quote of the Moment: Make it idiot proof and someone will make a better idiot. Quote of the Moment: He who laughs last thinks slowest!
【程序注解】 在客戶端的main()方法中,第13行實(shí)例化了一個(gè)MulticastSocket對(duì)象socket,然后用join()方法加入了組播組136.122.133.1。在for循環(huán)中接收了5個(gè)數(shù)據(jù)包,并把數(shù)據(jù)包中的內(nèi)容顯示出來(lái)(第18~25行)。最后在第27行離開(kāi)組播組(leaveGroup()),第28行關(guān) |