




已閱讀5頁,還剩17頁未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
用Java開發(fā)網(wǎng)絡(luò)軟件非常方便和強(qiáng)大,Java的這種力量來源于他獨(dú)有的一套強(qiáng)大的用于網(wǎng)絡(luò)的 API,這些API是一系列的類和接口,均位于包和中。在這篇文章中我們將介紹套接字(Socket)慨念,同時(shí)以實(shí)例說明如何使用Network API操縱套接字,在完成本文后,你就可以編寫網(wǎng)絡(luò)低端通訊軟件。什么是套接字(Socket)?Network API是典型的用于基于TCP/IP網(wǎng)絡(luò)Java程序與其他程序通訊,Network API依靠Socket進(jìn)行通訊。Socket可以看成在兩個(gè)程序進(jìn)行通訊連接中的一個(gè)端點(diǎn),一個(gè)程序?qū)⒁欢涡畔懭隨ocket中,該Socket將這段信息發(fā)送給另外一個(gè)Socket中,使這段信息能傳送到其他程序中。如圖1我們來分析一下圖1,Host A上的程序A將一段信息寫入Socket中,Socket的內(nèi)容被Host A的網(wǎng)絡(luò)管理軟件訪問,并將這段信息通過Host A的網(wǎng)絡(luò)接口卡發(fā)送到Host B,Host B的網(wǎng)絡(luò)接口卡接收到這段信息后,傳送給Host B的網(wǎng)絡(luò)管理軟件,網(wǎng)絡(luò)管理軟件將這段信息保存在Host B的Socket中,然后程序B才能在Socket中閱讀這段信息。假設(shè)在圖1的網(wǎng)絡(luò)中添加第三個(gè)主機(jī)Host C,那么Host A怎么知道信息被正確傳送到Host B而不是被傳送到Host C中了呢?基于TCP/IP網(wǎng)絡(luò)中的每一個(gè)主機(jī)均被賦予了一個(gè)唯一的IP地址,IP地址是一個(gè)32位的無符號整數(shù),由于沒有轉(zhuǎn)變成二進(jìn)制,因此通常以小數(shù)點(diǎn)分隔,如:,正如所見IP地址均由四個(gè)部分組成,每個(gè)部分的范圍都是0-255,以表示8位地址。值得注意的是IP地址都是32位地址,這是IP協(xié)議版本4(簡稱Ipv4)規(guī)定的,目前由于IPv4地址已近耗盡,所以IPv6地址正逐漸代替Ipv4地址,Ipv6地址則是128位無符號整數(shù)。假設(shè)第二個(gè)程序被加入圖1的網(wǎng)絡(luò)的Host B中,那么由Host A傳來的信息如何能被正確的傳給程序B而不是傳給新加入的程序呢?這是因?yàn)槊恳粋€(gè)基于TCP/IP網(wǎng)絡(luò)通訊的程序都被賦予了唯一的端口和端口號,端口是一個(gè)信息緩沖區(qū),用于保留Socket中的輸入/輸出信息,端口號是一個(gè)16位無符號整數(shù),范圍是0-65535,以區(qū)別主機(jī)上的每一個(gè)程序(端口號就像房屋中的房間號),低于256的短口號保留給標(biāo)準(zhǔn)應(yīng)用程序,比如pop3的端口號就是110,每一個(gè)套接字都組合進(jìn)了IP地址、端口、端口號,這樣形成的整體就可以區(qū)別每一個(gè)套接字t,下面我們就來談?wù)剝煞N套接字:流套接字和自尋址數(shù)據(jù)套接字。流套接字(Stream Socket)無論何時(shí),在兩個(gè)網(wǎng)絡(luò)應(yīng)用程序之間發(fā)送和接收信息時(shí)都需要建立一個(gè)可靠的連接,流套接字依靠TCP協(xié)議來保證信息正確到達(dá)目的地,實(shí)際上,IP包有可能在網(wǎng)絡(luò)中丟失或者在傳送過程中發(fā)生錯(cuò)誤,任何一種情況發(fā)生,作為接受方的 TCP將聯(lián)系發(fā)送方TCP重新發(fā)送這個(gè)IP包。這就是所謂的在兩個(gè)流套接字之間建立可靠的連接。流套接字在C/S程序中扮演一個(gè)必需的角色,客戶機(jī)程序(需要訪問某些服務(wù)的網(wǎng)絡(luò)應(yīng)用程序)創(chuàng)建一個(gè)扮演服務(wù)器程序的主機(jī)的IP地址和服務(wù)器程序(為客戶端應(yīng)用程序提供服務(wù)的網(wǎng)絡(luò)應(yīng)用程序)的端口號的流套接字對象??蛻舳肆魈捉幼值某跏蓟a將IP地址和端口號傳遞給客戶端主機(jī)的網(wǎng)絡(luò)管理軟件,管理軟件將IP地址和端口號通過NIC傳遞給服務(wù)器端主機(jī);服務(wù)器端主機(jī)讀到經(jīng)過NIC傳遞來的數(shù)據(jù),然后查看服務(wù)器程序是否處于監(jiān)聽狀態(tài),這種監(jiān)聽依然是通過套接字和端口來進(jìn)行的;如果服務(wù)器程序處于監(jiān)聽狀態(tài),那么服務(wù)器端網(wǎng)絡(luò)管理軟件就向客戶機(jī)網(wǎng)絡(luò)管理軟件發(fā)出一個(gè)積極的響應(yīng)信號,接收到響應(yīng)信號后,客戶端流套接字初始化代碼就給客戶程序建立一個(gè)端口號,并將這個(gè)端口號傳遞給服務(wù)器程序的套接字(服務(wù)器程序?qū)⑹褂眠@個(gè)端口號識別傳來的信息是否是屬于客戶程序)同時(shí)完成流套接字的初始化。如果服務(wù)器程序沒有處于監(jiān)聽狀態(tài),那么服務(wù)器端網(wǎng)絡(luò)管理軟件將給客戶端傳遞一個(gè)消極信號,收到這個(gè)消極信號后,客戶程序的流套接字初始化代碼將拋出一個(gè)異常對象并且不建立通訊連接,也不創(chuàng)建流套接字對象。這種情形就像打電話一樣,當(dāng)有人的時(shí)候通訊建立,否則電話將被掛起。這部分的工作包括了相關(guān)聯(lián)的三個(gè)類:InetAddress, Socket, 和 ServerSocket。 InetAddress對象描繪了32位或128位IP地址,Socket對象代表了客戶程序流套接字,ServerSocket代表了服務(wù)程序流套接字,所有這三個(gè)類均位于包中。InetAddress類InetAddress類在網(wǎng)絡(luò)API套接字編程中扮演了一個(gè)重要角色。參數(shù)傳遞給流套接字類和自尋址套接字類構(gòu)造器或非構(gòu)造器方法。InetAddress描述了32位或64位IP地址,要完成這個(gè)功能,InetAddress類主要依靠兩個(gè)支持類Inet4Address 和 Inet6Address,這三個(gè)類是繼承關(guān)系,InetAddrress是父類,Inet4Address 和 Inet6Address是子類。由于InetAddress類只有一個(gè)構(gòu)造函數(shù),而且不能傳遞參數(shù),所以不能直接創(chuàng)建InetAddress對象,比如下面的做法就是錯(cuò)誤的:InetAddress ia = new InetAddress (); 但我們可以通過下面的5個(gè)工廠方法創(chuàng)建來創(chuàng)建一個(gè)InetAddress對象或InetAddress數(shù)組:. getAllByName(String host)方法返回一個(gè)InetAddress對象的引用,每個(gè)對象包含一個(gè)表示相應(yīng)主機(jī)名的單獨(dú)的IP地址,這個(gè)IP地址是通過host參數(shù)傳遞的,對于指定的主機(jī)如果沒有IP地址存在那么這個(gè)方法將拋出一個(gè)UnknownHostException 異常對象。. getByAddress(byte addr)方法返回一個(gè)InetAddress對象的引用,這個(gè)對象包含了一個(gè)Ipv4地址或Ipv6地址,Ipv4地址是一個(gè)4字節(jié)數(shù)組,Ipv6地址是一個(gè)16字節(jié)地址數(shù)組,如果返回的數(shù)組既不是4字節(jié)的也不是16字節(jié)的,那么方法將會(huì)拋出一個(gè)UnknownHostException異常對象。. getByAddress(String host, byte addr)方法返回一個(gè)InetAddress對象的引用,這個(gè)InetAddress對象包含了一個(gè)由host和4字節(jié)的addr數(shù)組指定的IP地址,或者是host和16字節(jié)的addr數(shù)組指定的IP地址,如果這個(gè)數(shù)組既不是4字節(jié)的也不是16位字節(jié)的,那么該方法將拋出一個(gè)UnknownHostException異常對象。. getByName(String host)方法返回一個(gè)InetAddress對象,該對象包含了一個(gè)與host參數(shù)指定的主機(jī)相對應(yīng)的IP地址,對于指定的主機(jī)如果沒有IP地址存在,那么方法將拋出一個(gè)UnknownHostException異常對象。. getLocalHost()方法返回一個(gè)InetAddress對象,這個(gè)對象包含了本地機(jī)的IP地址,考慮到本地主機(jī)既是客戶程序主機(jī)又是服務(wù)器程序主機(jī),為避免混亂,我們將客戶程序主機(jī)稱為客戶主機(jī),將服務(wù)器程序主機(jī)稱為服務(wù)器主機(jī)。上面講到的方法均提到返回一個(gè)或多個(gè)InetAddress對象的引用,實(shí)際上每一個(gè)方法都要返回一個(gè)或多個(gè)Inet4Address/Inet6Address對象的引用,調(diào)用者不需要知道引用的子類型,相反調(diào)用者可以使用返回的引用調(diào)用InetAddress對象的非靜態(tài)方法,包括子類型的多態(tài)以確保重載方法被調(diào)用。InetAddress和它的子類型對象處理主機(jī)名到主機(jī)IPv4或IPv6地址的轉(zhuǎn)換,要完成這個(gè)轉(zhuǎn)換需要使用域名系統(tǒng),下面的代碼示范了如何通過調(diào)用getByName(String host)方法獲得InetAddress子類對象的方法,這個(gè)對象包含了與host參數(shù)相對應(yīng)的IP地址:InetAddress ia = InetAddress.getByName (); 一但獲得了InetAddress子類對象的引用就可以調(diào)用InetAddress的各種方法來獲得InetAddress子類對象中的IP地址信息,比如,可以通過調(diào)用getCanonicalHostName()從域名服務(wù)中獲得標(biāo)準(zhǔn)的主機(jī)名;getHostAddress()獲得IP地址,getHostName()獲得主機(jī)名,isLoopbackAddress()判斷IP地址是否是一個(gè)loopback地址。List1 是一段示范代碼:InetAddressDemo/ InetAddressDemo.javaimport .*;class InetAddressDemopublic static void main (String args) throws UnknownHostExceptionString host = localhost;if (args.length = 1)host = args 0;InetAddress ia = InetAddress.getByName (host);System.out.println (Canonical Host Name = +ia.getCanonicalHostName ();System.out.println (Host Address = +ia.getHostAddress ();System.out.println (Host Name = +ia.getHostName ();System.out.println (Is Loopback Address = +ia.isLoopbackAddress (); 當(dāng)無命令行參數(shù)時(shí),代碼輸出類似下面的結(jié)果:Canonical Host Name = localhostHost Address = Host Name = localhostIs Loopback Address = true InetAddressDemo給了你一個(gè)指定主機(jī)名作為命令行參數(shù)的選擇,如果沒有主機(jī)名被指定,那么將使用localhost(客戶機(jī)的),InetAddressDemo通過調(diào)用getByName(String host)方法獲得一個(gè)InetAddress子類對象的引用,通過這個(gè)引用獲得了標(biāo)準(zhǔn)主機(jī)名,主機(jī)地址,主機(jī)名以及IP地址是否是loopback地址的輸出。Socket類當(dāng)客戶程序需要與服務(wù)器程序通訊的時(shí)候,客戶程序在客戶機(jī)創(chuàng)建一個(gè)socket對象,Socket類有幾個(gè)構(gòu)造函數(shù)。兩個(gè)常用的構(gòu)造函數(shù)是 Socket(InetAddress addr, int port) 和 Socket(String host, int port),兩個(gè)構(gòu)造函數(shù)都創(chuàng)建了一個(gè)基于Socket的連接服務(wù)器端流套接字的流套接字。對于第一個(gè)InetAddress子類對象通過addr參數(shù)獲得服務(wù)器主機(jī)的IP地址,對于第二個(gè)函數(shù)host參數(shù)包被分配到InetAddress對象中,如果沒有IP地址與host參數(shù)相一致,那么將拋出UnknownHostException異常對象。兩個(gè)函數(shù)都通過參數(shù)port獲得服務(wù)器的端口號。假設(shè)已經(jīng)建立連接了,網(wǎng)絡(luò)API將在客戶端基于Socket的流套接字中捆綁客戶程序的IP地址和任意一個(gè)端口號,否則兩個(gè)函數(shù)都會(huì)拋出一個(gè)IOException對象。如果創(chuàng)建了一個(gè)Socket對象,那么它可能通過調(diào)用Socket的 getInputStream()方法從服務(wù)程序獲得輸入流讀傳送來的信息,也可能通過調(diào)用Socket的 getOutputStream()方法獲得輸出流來發(fā)送消息。在讀寫活動(dòng)完成之后,客戶程序調(diào)用close()方法關(guān)閉流和流套接字,下面的代碼創(chuàng)建了一個(gè)服務(wù)程序主機(jī)地址為,端口號為13的Socket對象,然后從這個(gè)新創(chuàng)建的Socket對象中讀取輸入流,然后再關(guān)閉流和Socket對象。Socket s = new Socket (, 13);InputStream is = s.getInputStream ();/ Read from the stream.is.close ();s.close (); 接下面我們將示范一個(gè)流套接字的客戶程序,這個(gè)程序?qū)?chuàng)建一個(gè)Socket對象,Socket將訪問運(yùn)行在指定主機(jī)端口10000上的服務(wù)程序,如果訪問成功客戶程序?qū)⒔o服務(wù)程序發(fā)送一系列命令并打印服務(wù)程序的響應(yīng)。List2使我們創(chuàng)建的程序SSClient的源代碼:Listing 2: SSClient.java/ SSClient.javaimport java.io.*;import .*; class SSClientpublic static void main (String args)String host = localhost;/ If user specifies a command-line argument, that argument/ represents the host name.if (args.length = 1)host = args 0;BufferedReader br = null;PrintWriter pw = null;Socket s = null;try/ Create a socket that attempts to connect to the server/ program on the host at port 10000.s = new Socket (host, 10000);/ Create an input stream reader that chains to the sockets/ byte-oriented input stream. The input stream reader/ converts bytes read from the socket to characters. The/ conversion is based on the platforms default character/ set.InputStreamReader isr;isr = new InputStreamReader (s.getInputStream ();/ Create a buffered reader that chains to the input stream/ reader. The buffered reader supplies a convenient method/ for reading entire lines of text.br = new BufferedReader (isr);/ Create a print writer that chains to the sockets byte-/ oriented output stream. The print writer creates an/ intermediate output stream writer that converts/ characters sent to the socket to bytes. The conversion/ is based on the platforms default character set.pw = new PrintWriter (s.getOutputStream (), true);/ Send the DATE command to the server.pw.println (DATE);/ Obtain and print the current date/time.System.out.println (br.readLine ();/ Send the PAUSE command to the server. This allows several/ clients to start and verifies that the server is spawning/ multiple threads.pw.println (PAUSE);/ Send the DOW command to the server.pw.println (DOW);/ Obtain and print the current day of week.System.out.println (br.readLine ();/ Send the DOM command to the server.pw.println (DOM);/ Obtain and print the current day of month.System.out.println (br.readLine ();/ Send the DOY command to the server.pw.println (DOY);/ Obtain and print the current day of year.System.out.println (br.readLine ();catch (IOException e)System.out.println (e.toString ();finallytryif (br != null)br.close ();if (pw != null)pw.close ();if (s != null)s.close ();catch (IOException e) 運(yùn)行這段程序?qū)?huì)得到下面的結(jié)果:Tue Jan 29 18:11:51 CST 2002TUESDAY2929 SSClient創(chuàng)建了一個(gè)Socket對象與運(yùn)行在主機(jī)端口10000的服務(wù)程序聯(lián)系,主機(jī)的IP地址由host變量確定。SSClient將獲得Socket的輸入輸出流,圍繞BufferedReader的輸入流和PrintWriter的輸出流對字符串進(jìn)行讀寫操作就變得非常容易,SSClient個(gè)服務(wù)程序發(fā)出各種date/time命令并得到響應(yīng),每個(gè)響應(yīng)均被打印,一旦最后一個(gè)響應(yīng)被打印,將執(zhí)行Try/Catch/Finally結(jié)構(gòu)的Finally子串,F(xiàn)inally子串將在關(guān)閉Socket之前關(guān)閉BufferedReader 和 PrintWriter。在SSClient源代碼編譯完成后,可以輸入java SSClient 來執(zhí)行這段程序,如果有合適的程序運(yùn)行在不同的主機(jī)上,采用主機(jī)名/IP地址為參數(shù)的輸入方式,比如是運(yùn)行服務(wù)器程序的主機(jī),那么輸入方式就是java SSClient 。技巧Socket類包含了許多有用的方法。比如getLocalAddress()將返回一個(gè)包含客戶程序IP地址的InetAddress子類對象的引用;getLocalPort()將返回客戶程序的端口號;getInetAddress()將返回一個(gè)包含服務(wù)器IP地址的InetAddress子類對象的引用;getPort()將返回服務(wù)程序的端口號。ServerSocket類由于SSClient使用了流套接字,所以服務(wù)程序也要使用流套接字。這就要?jiǎng)?chuàng)建一個(gè)ServerSocket對象,ServerSocket有幾個(gè)構(gòu)造函數(shù),最簡單的是ServerSocket(int port),當(dāng)使用ServerSocket(int port)創(chuàng)建一個(gè)ServerSocket對象,port參數(shù)傳遞端口號,這個(gè)端口就是服務(wù)器監(jiān)聽連接請求的端口,如果在這時(shí)出現(xiàn)錯(cuò)誤將拋出IOException異常對象,否則將創(chuàng)建ServerSocket對象并開始準(zhǔn)備接收連接請求。接下來服務(wù)程序進(jìn)入無限循環(huán)之中,無限循環(huán)從調(diào)用ServerSocket的accept()方法開始,在調(diào)用開始后accept()方法將導(dǎo)致調(diào)用線程阻塞直到連接建立。在建立連接后accept()返回一個(gè)最近創(chuàng)建的Socket對象,該Socket對象綁定了客戶程序的IP地址或端口號。由于存在單個(gè)服務(wù)程序與多個(gè)客戶程序通訊的可能,所以服務(wù)程序響應(yīng)客戶程序不應(yīng)該花很多時(shí)間,否則客戶程序在得到服務(wù)前有可能花很多時(shí)間來等待通訊的建立,然而服務(wù)程序和客戶程序的會(huì)話有可能是很長的(這與電話類似),因此為加快對客戶程序連接請求的響應(yīng),典型的方法是服務(wù)器主機(jī)運(yùn)行一個(gè)后臺線程,這個(gè)后臺線程處理服務(wù)程序和客戶程序的通訊。為了示范我們在上面談到的慨念并完成SSClient程序,下面我們創(chuàng)建一個(gè)SSServer程序,程序?qū)?chuàng)建一個(gè)ServerSocket對象來監(jiān)聽端口10000的連接請求,如果成功服務(wù)程序?qū)⒌却B接輸入,開始一個(gè)線程處理連接,并響應(yīng)來自客戶程序的命令。下面就是這段程序的代碼:Listing 3: SSServer.java/ SSServer.javaimport java.io.*;import .*;import java.util.*;class SSServerpublic static void main (String args) throws IOExceptionSystem.out.println (Server starting.n); ServerSocket server = new ServerSocket (10000);while (true)Socket s = server.accept ();System.out.println (Accepting Connection.n);/ Start a thread to handle the connection.new ServerThread (s).start ();/供SSServer.java使用的外部類ServerThread.javaclass ServerThread extends Threadprivate Socket s;ServerThread (Socket s)this.s = s;public void run ()BufferedReader br = null;PrintWriter pw = null;try/ Create an input stream reader that chains to the sockets/ byte-oriented input stream. The input stream reader/ converts bytes read from the socket to characters. The/ conversion is based on the platforms default character/ set.InputStreamReader isr;isr = new InputStreamReader (s.getInputStream ();/ Create a buffered reader that chains to the input stream/ reader. The buffered reader supplies a convenient method/ for reading entire lines of text.br = new BufferedReader (isr);/ Create a print writer that chains to the sockets byte-/ oriented output stream. The print writer creates an/ intermediate output stream writer that converts/ characters sent to the socket to bytes. The conversion/ is based on the platforms default character set.pw = new PrintWriter (s.getOutputStream (), true);/ Create a calendar that makes it possible to obtain date/ and time information.Calendar c = Calendar.getInstance ();/ Because the client program may send multiple commands, a/ loop is required. Keep looping until the client either/ explicitly requests termination by sending a command/ beginning with letters BYE or implicitly requests/ termination by closing its output stream.do/ Obtain the client programs next command.String cmd = br.readLine ();/ Exit if client program has closed its output stream.if (cmd = null)break;/ Convert command to uppercase, for ease of comparison.cmd = cmd.toUpperCase ();/ If client program sends BYE command, terminate.if (cmd.startsWith (BYE)break;/ If client program sends DATE or TIME command, return/ current date/time to the client program.if (cmd.startsWith (DATE) | cmd.startsWith (TIME)pw.println (c.getTime ().toString ();/ If client program sends DOM (Day Of Month) command,/ return current day of month to the client program.if (cmd.startsWith (DOM)pw.println ( + c.get (Calendar.DAY_OF_MONTH);/ If client program sends DOW (Day Of Week) command,/ return current weekday (as a string) to the client/ program.if (cmd.startsWith (DOW)switch (c.get (Calendar.DAY_OF_WEEK)case Calendar.SUNDAY : pw.println (SUNDAY);break;case Calendar.MONDAY : pw.println (MONDAY);break;case Calendar.TUESDAY : pw.println (TUESDAY);break;case Calendar.WEDNESDAY: pw.println (WEDNESDAY);break;case Calendar.THURSDAY : pw.println (THURSDAY);break;case Calendar.FRIDAY : pw.println (FRIDAY);break;case Calendar.SATURDAY : pw.println (SATURDAY);/ If client program sends DOY (Day of Year) command,/ return current day of year to the client program.if (cmd.startsWith (DOY)pw.println ( + c.get (Calendar.DAY_OF_YEAR);/ If client program sends PAUSE command, sleep for three/ seconds.if (cmd.startsWith (PAUSE)tryThread.sleep (3000);catch (InterruptedException e)while (true);catch (IOException e)System.out.println (e.toString ();finallySystem.out.println (Closing Connection.n);tryif (br != null)br.close ();if (pw != null)pw.close ();if (s != null)s.close ();catch (IOException e) 運(yùn)行這段程序?qū)⒌玫较旅娴妮敵觯篠erver starting.Accepting Connection.Closing Connection. SSServer的源代碼聲明了一對類:SSServer 和ServerThread;SSServer的main()方法創(chuàng)建了一個(gè)ServerSocket對象來監(jiān)聽端口10000上的連接請求,如果成功, SSServer進(jìn)入一個(gè)無限循環(huán)中,交替調(diào)用ServerSocket的 accept() 方法來等待連接請求,同時(shí)啟動(dòng)后臺線程處理連接(accept()返回的請求)。線程由ServerThread繼承的start()方法開始,并執(zhí)行ServerThread的run()方法中的代碼。一旦run()方法運(yùn)行,線程將創(chuàng)建BufferedReader, PrintWriter和 Calendar對象并進(jìn)入一個(gè)循環(huán),這個(gè)循環(huán)由讀(通過BufferedReader的 readLine())來自客戶程序的一行文本開始,文本(命令)存儲(chǔ)在cmd引用的string對象中,如果客戶程序過早的關(guān)閉輸出流,會(huì)發(fā)生什么呢?答案是:cmd將得不到賦值。注意必須考慮到這種情況:在服務(wù)程序正在讀輸入流時(shí),客戶程序關(guān)閉了輸出流,如果沒有對這種情況進(jìn)行處理,那么程序?qū)a(chǎn)生異常。一旦編譯了SSServer的源代碼,通過輸入Java SSServer來運(yùn)行程序,在開始運(yùn)行SSServer后,就可以運(yùn)行一個(gè)或多個(gè)SSClient程序。自尋址套接字(Datagram Sockets) ,因?yàn)槭褂昧魈捉幼值拿總€(gè)連接均要花費(fèi)一定的時(shí)間,要減少這種開銷,網(wǎng)絡(luò)API提供了第二種套接字:自尋址套接字(datagram socket),自尋址使用UDP發(fā)送尋址信息(從客戶程序到服務(wù)程序或從服務(wù)程序到客戶程序),不同的是可以通過自尋址套接字發(fā)送多IP信息包,自尋址信息包含在自尋址包中,此外自尋址包又包含在IP包內(nèi),這就將尋址信息長度限制在60000字節(jié)內(nèi)。圖2顯示了位于IP包內(nèi)的自尋址包的自尋址信息。與TCP保證信息到達(dá)信息目的地的方式不同,UDP提供了另外一種方法,如果自尋址信息包沒有到達(dá)目的地,那么UDP也不會(huì)請求發(fā)送者重新發(fā)送自尋址包,這是因?yàn)閁DP在每一個(gè)自尋址包中包含了錯(cuò)誤檢測信息,在每個(gè)自尋址包到達(dá)目的地之后UDP只進(jìn)行簡單的錯(cuò)誤檢查,如果檢測失敗,UDP將拋棄這個(gè)自尋址包,也不會(huì)從發(fā)送者那里重新請求替代者,這與通過郵局發(fā)送信件相似,發(fā)信人在發(fā)信之前不需要與收信人建立連接,同樣也不能保證信件能到達(dá)收信人那里自尋址套接字工作包括下面三個(gè)類:DatagramPacket, DatagramSocket,和 MulticastSocket。DatagramPacket對象描繪了自尋址包的地址信息,DatagramSocket表示客戶程序和服務(wù)程序自尋址套接字,MulticastSocket描繪了能進(jìn)行多點(diǎn)傳送的自尋址套接字,這三個(gè)類均位于包內(nèi)。DatagramPacket類在使用自尋址包之前,你需要首先熟悉DatagramPacket類,地址信息和自尋址包以字節(jié)數(shù)組的方式同時(shí)壓縮入這個(gè)類創(chuàng)建的對象中DatagramPacket有數(shù)個(gè)構(gòu)造函數(shù),即使這些構(gòu)造函數(shù)的形式不同,但通常情況下他們都有兩個(gè)共同的參數(shù):byte buffer 和 int length,buffer參數(shù)包含了一個(gè)對保存自尋址數(shù)據(jù)包信息的字節(jié)數(shù)組的引用,length表示字節(jié)數(shù)組的長度。最簡單的構(gòu)造函數(shù)是DatagramPacket(byte buffer, int length),這個(gè)構(gòu)造函數(shù)確定了自尋址數(shù)據(jù)包數(shù)組和數(shù)組的長度,但沒有任何自尋址數(shù)據(jù)包的地址和端口信息,這些信息可以后面通過調(diào)用方法setAddress(InetAddress addr)和setPort(int port)添加上,下面的代碼示范了這些函數(shù)和方法。byte buffer = new byte 100;DatagramPacket dgp = new DatagramPacket (buffer, buffer.length);InetAddress ia = InetAddress.getByName ();dgp.setAddress (ia);dgp.setPort (6000); / Send datagram packet to port 6000. 如果你更喜歡在調(diào)用構(gòu)造函數(shù)的時(shí)候同時(shí)包括地址和端口號,可以使用DatagramPacket(byte buffer, int length, InetAddress addr, int port)函數(shù),下面的代碼示范了另外一種選擇。byte buffer = new byte 100;InetAddress ia = InetAddress.getByName ();DatagramPacket dgp = new DatagramPacket (buffer, buffer.length, ia, 6000); 有時(shí)候在創(chuàng)建了DatagramPacket對象后想改變字節(jié)數(shù)組和他的長度,這時(shí)可以通過調(diào)用setData(byte buffer) 和 setLength(int length)方法來實(shí)現(xiàn)。在任何時(shí)候都可以通過調(diào)用getData() 來得到字節(jié)數(shù)組的引用,通過調(diào)用getLength()來獲得字節(jié)數(shù)組的長度。下面的代碼示范了這些方法:byte buffer2 = new byte 256;dgp.setData (buffer2);dgp.setLength (buffer2.length); 關(guān)于DatagramPacket的更多信息請參考SDK文檔。DatagramSocket類DatagramSocket類在客戶端創(chuàng)建自尋址套接字與服務(wù)器端進(jìn)行通信連接,并發(fā)送和接受自尋址套接字。雖然有多個(gè)構(gòu)造函數(shù)可供選擇,但我發(fā)現(xiàn)創(chuàng)建客戶端自尋址套接字最便利的選擇是DatagramSocket()函數(shù),而服務(wù)器端則是DatagramSocket(int port)函數(shù),如果未能創(chuàng)建自尋址套接字或綁定自尋址套接字到本地端口,那么這兩個(gè)函數(shù)都將拋出一個(gè)SocketException對象,一旦程序創(chuàng)建了DatagramSocket對象,那么程序分別調(diào)用send(DatagramPacket dgp)和 receive(DatagramPacket dgp)來發(fā)送和接收自尋址數(shù)據(jù)包,List4顯示的DGSClient源代碼示范了如何創(chuàng)建自尋址套接字以及如何通過套接字處理發(fā)送和接收信息Listing 4: DGSClient.java/ DGSClient.javaimport java.io.*;import .*;class DGSClientpublic static void main (String args)String host = localhost;/ If user specifies a command-line argument, that argument/ represents the host name.if (args.length = 1)host = args 0;DatagramSocket s = null;try/ Create a datagram socket bound to an arbitrary port.s = new DatagramSocket ();/ Create a byte array that will hold the data portion of a/ datagram packets message. That message originates as a/ String object, which gets converted to a sequence of/ bytes when Strings getBytes() method is called. The/ conversion uses the platforms default character set.byte buffer;buffer = new String (Send me a datagram).getB
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年血液透析器項(xiàng)目申請報(bào)告
- 2025年美發(fā)師(高級)考試試卷:美發(fā)行業(yè)市場調(diào)研與競爭對手分析
- 2025年電腦提花人造毛皮機(jī)項(xiàng)目立項(xiàng)申請報(bào)告
- 我的寵物生活寫物并抒情類作文14篇
- 2025年電工(高級技師)職業(yè)技能鑒定實(shí)操試卷:電氣自動(dòng)化技術(shù)技能案例分析
- 2025年安全生產(chǎn)管理工程師模擬試題
- 家庭經(jīng)濟(jì)情況與收入支出平衡證明(8篇)
- 清(梅)酒介紹試題
- 2025年旅游地產(chǎn)項(xiàng)目生態(tài)旅游規(guī)劃與設(shè)計(jì)策略研究
- 2025年城市生活垃圾分類處理創(chuàng)新實(shí)踐與公眾教育體系研究報(bào)告001
- 2024年全國《汽車加氣站操作工》安全基礎(chǔ)知識考試題庫與答案
- 胰島素注射 課件
- 公司事故隱患內(nèi)部報(bào)告獎(jiǎng)勵(lì)機(jī)制
- 【教育數(shù)字化應(yīng)用案例】初中物理教育數(shù)字化應(yīng)用案例
- 北京市西城區(qū)2021-2022學(xué)年八年級下學(xué)期期末歷史試題(試題+答案)
- 貴州省銅仁市2023-2024學(xué)年七年級下學(xué)期期末生物試題(解析版)
- 供應(yīng)商定期評價(jià)表(精簡版)
- HJ 620-2011 水質(zhì) 揮發(fā)性鹵代烴的測定 頂空氣相色譜法
- 廣西壯族自治區(qū)桂林市2023-2024學(xué)年七年級下學(xué)期期末考試數(shù)學(xué)試題
- 企業(yè)所得稅匯算清繳申報(bào)表電子表格版(帶公式-自動(dòng)計(jì)算)
- 訂婚解除婚約協(xié)議書模板
評論
0/150
提交評論