用Java 編寫客戶服務(wù)器程序_第1頁
用Java 編寫客戶服務(wù)器程序_第2頁
用Java 編寫客戶服務(wù)器程序_第3頁
用Java 編寫客戶服務(wù)器程序_第4頁
用Java 編寫客戶服務(wù)器程序_第5頁
已閱讀5頁,還剩43頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、1.5 用Java 編寫客戶/服務(wù)器程序n在Java中,有三種套接字類:.Socket、.ServerSocket和DatagramSocket。其中Socket和ServerSocket類建立在TCP協(xié)議基礎(chǔ)上,DatagramSocket 類建立在UDP協(xié)議基礎(chǔ)上。n傳輸層向應(yīng)用層提供了套接字Socket 接口,Socket 封裝了下層的數(shù)據(jù)傳輸細(xì)節(jié),應(yīng)用層的程序通過Socket來建立與遠(yuǎn)程主機(jī)的連接以及進(jìn)行數(shù)據(jù)傳輸。圖1-18 套接字可看過是通信連接兩端的收發(fā)器1.5.1 創(chuàng)建EchoServer圖1-19 服務(wù)器與客戶利用ServerSocket 和Socket來通信1.5.1 創(chuàng)建E

2、choServern服務(wù)器程序通過一直監(jiān)聽端口,來接收客戶程序的連接請求。在服務(wù)器程序中,需要先創(chuàng)建一個ServerSocket對象,在構(gòu)造方法中指定監(jiān)聽的端口: ServerSocket server=new ServerSocket(8000); /監(jiān)聽8000端口nServerSocket的構(gòu)造方法負(fù)責(zé)在操作系統(tǒng)中把當(dāng)前進(jìn)程注冊為服務(wù)器進(jìn)程。服務(wù)器程序接下來調(diào)用ServerSocket 對象的accept()方法,該方法一直監(jiān)聽端口,等待客戶的連接請求,如果接收到一個連接請求,accept()方法就會返回一個Socket 對象,這個Socket對象與客戶端的Socket對象形成了一條通信

3、線路: Socket socket=server.accept(); /等待客戶的連接請求1.5.1 創(chuàng)建EchoServernSocket 類提供了getInputStream()方法和getOutputStream()方法,分別返回輸入流InputStream 對象和輸出流OutputStream 對象。程序只需向輸出流寫數(shù)據(jù),就能向?qū)Ψ桨l(fā)送數(shù)據(jù);只需從輸入流讀數(shù)據(jù),就能接收來自對方的數(shù)據(jù)。n與普通I/O流一樣,Socket 的輸入流和輸出流也可以用過濾流來裝飾。在以下代碼中,先獲得輸出流,然后用PrintWriter 裝飾它,PrintWriter 的println()方法能夠?qū)懸恍袛?shù)據(jù)

4、;以下代碼接著獲得輸入流,然后用BufferedReader 裝飾它,BufferedReader 的readLine()方法能夠讀入一行數(shù)據(jù): OutputStream socketOut = socket.getOutputStream(); /參數(shù)true 表示每寫一行,PrintWriter緩存就自動溢出,把數(shù)據(jù)寫到目的地 PrintWriter pw=new PrintWriter(socketOut,true); InputStream socketIn = socket.getInputStream(); BufferedReader br=new BufferedReader(

5、new InputStreamReader(socketIn);1.5.1 創(chuàng)建EchoServern例程1-2 EchoServer.javaimport java.io.*;import .*;public class EchoServer private int port=8000; private ServerSocket serverSocket; public EchoServer() throws IOException serverSocket = new ServerSocket(port); System.out.println(服務(wù)器啟動); public String

6、echo(String msg) return echo: + msg; private PrintWriter getWriter(Socket socket)throws IOException OutputStream socketOut = socket.getOutputStream();1.5.1 創(chuàng)建EchoServer return new PrintWriter(socketOut,true); private BufferedReader getReader(Socket socket)throws IOException InputStream socketIn = so

7、cket.getInputStream(); return new BufferedReader(new InputStreamReader(socketIn); public void service() while (true) Socket socket=null; try socket = serverSocket.accept(); /等待客戶連接 System.out.println(New connection accepted +socket.getInetAddress() + : +socket.getPort(); BufferedReader br =getReader

8、(socket); PrintWriter pw = getWriter(socket); String msg = null;1.5.1 創(chuàng)建EchoServer while (msg = br.readLine() != null) System.out.println(msg); pw.println(echo(msg); if (msg.equals(bye) /如果客戶發(fā)送消息為“bye”,就結(jié)束通信 break; catch (IOException e) e.printStackTrace(); finally try if(socket!=null) socket.close(

9、); /斷開連接 catch (IOException e) e.printStackTrace(); / service() 方法結(jié)束 public static void main(String args)throws IOException new EchoServer().service(); 1.5.2 創(chuàng)建EchoClientn在EchoClient程序中,為了與EchoServer通信,需要先創(chuàng)建一個Socket 對象: String host=localhost; String port=8000; Socket socket=new Socket(host,port);n當(dāng)參

10、數(shù)host 的取值為“l(fā)ocalhost”,表示EchoClient與EchoServer進(jìn)程運行在同一個主機(jī)上。如果Socket對象成功創(chuàng)建,就表示建立了EchoClient與EchoServer 之間的連接。接下來,EchoClient 從Socket 對象中得到了輸出流和輸入流,就能與EchoServer 交換數(shù)據(jù)。1.5.2 創(chuàng)建EchoClientimport .*;import java.io.*;import java.util.*;public class EchoClient private String host=localhost; private int port=80

11、00; private Socket socket; public EchoClient()throws IOException socket=new Socket(host,port); public static void main(String args)throws IOException new EchoClient().talk(); 1.5.2 創(chuàng)建EchoClientprivate PrintWriter getWriter(Socket socket)throws IOException OutputStream socketOut = socket.getOutputStr

12、eam(); return new PrintWriter(socketOut,true); private BufferedReader getReader(Socket socket)throws IOException InputStream socketIn = socket.getInputStream(); return new BufferedReader(new InputStreamReader(socketIn); public void talk()throws IOException try BufferedReader br=getReader(socket); Pr

13、intWriter pw=getWriter(socket); BufferedReader localReader=new BufferedReader(new InputStreamReader(System.in); String msg=null; while(msg=localReader.readLine()!=null)1.5.2 創(chuàng)建EchoClient pw.println(msg); System.out.println(br.readLine(); if(msg.equals(bye) break; catch(IOException e) e.printStackTra

14、ce(); finally trysocket.close();catch(IOException e)e.printStackTrace(); 運行EchoServer和EchoClientn運行范例時,需要打開兩個DOS 界面,先在一個DOS 界面中運行“java EchoServer”命令,再在另一個DOS界面中運行“java EchoClient”命令。圖1-20 顯示了運行這兩個程序的DOS界面。在EchoClient 控制臺,用戶輸入字符串“hi”,程序就會輸出“echo:hi”第2章 Socket用法詳解 參考Java網(wǎng)絡(luò)編程精解的第2章n2.1 構(gòu)造Socketn2.2 獲取S

15、ocket的信息n2.3 關(guān)閉Socketn2.4 半關(guān)閉Socketn2.5 設(shè)置Socket的選項n2.6 發(fā)送郵件的SMTP客戶程序2.1 構(gòu)造SocketnSocket的構(gòu)造方法有以下幾種重載形式:n(1)Socket() n(2)Socket(InetAddress address, int port)throws UnknownHostException,IOException n(3)Socket(InetAddress address, int port, InetAddress localAddr, int localPort)throws IOException n(4)S

16、ocket(String host, int port) throws UnknownHostException,IOException n(5)Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException 2.1.1 設(shè)定等待建立連接的超時時間 n設(shè)定等待建立連接的超時時間Socket socket=new Socket();SocketAddress remoteAddr=new InetSocketAddress(localhost,8000);/等待建立連接的超時時間為1分鐘

17、socket.connect(remoteAddr, 60000); 2.1.2 設(shè)定服務(wù)器的地址nSocket(InetAddress address, int port) Socket(String host, int port) nInetAddress的用法如下:/返回本地主機(jī)的IP地址InetAddress addr1=InetAddress.getLocalHost(); /返回代表的IP地址InetAddress addr2=InetAddress.getByName(); /返回域名為的IP地址Ine

18、tAddress addr3=InetAddress.getByName(); 2.1.3 設(shè)定客戶端的地址n在一個Socket對象中,既包含遠(yuǎn)程服務(wù)器的IP地址和端口信息,也包含本地客戶端的IP地址和端口信息。默認(rèn)情況下,客戶端的IP地址來自于客戶程序所在的主機(jī),客戶端的端口則由操作系統(tǒng)隨機(jī)分配。Socket類還有兩個構(gòu)造方法允許顯式的設(shè)置客戶端的IP地址和端口:nSocket(InetAddress address, int port, InetAddress localAddr, int localPort)throws IOException nS

19、ocket(String host, int port, InetAddress localAddr, int localPort) throws IOException 2.1.4 客戶連接服務(wù)器時可能拋出的異常n當(dāng)Socket的構(gòu)造方法請求連接服務(wù)器時,可能會拋出以下異常:nUnknownHostException:如果無法識別主機(jī)的名字或IP地址,就會拋出這種異常。nConnectException:如果沒有服務(wù)器進(jìn)程監(jiān)聽指定的端口,或者服務(wù)器進(jìn)程拒絕連接,就會拋出這種異常。nSocketTimeoutException:如果等待連接超時,就會拋出這種異常。nBindException:

20、如果無法把Socket對象與指定的本地IP地址或端口綁定,就會拋出這種異常。2.1.4 客戶連接服務(wù)器時可能拋出的異常2.1.4 客戶連接服務(wù)器時可能拋出的異常n拋出UnknownHostException的情況:如果無法識別主機(jī)的名字或IP地址,就會拋出這種異常。n拋出ConnectException的情況:n沒有服務(wù)器進(jìn)程監(jiān)聽指定的端口。n服務(wù)器進(jìn)程拒絕連接。n拋出SocketTimeoutException的情況:如果客戶端等待連接超時,就會拋出這種異常。n拋出BindException的情況:如果無法把Socket對象與指定的本地IP地址或端口綁定,就會拋出這種異常。2.2 獲取Soc

21、ket的信息 n以下方法用于獲取Socket的有關(guān)信息:ngetInetAddress():獲得遠(yuǎn)程服務(wù)器的IP地址。ngetPort():獲得遠(yuǎn)程服務(wù)器的端口。ngetLocalAddress():獲得客戶本地的IP地址。ngetLocalPort():獲得客戶本地的端口。ngetInputStream():獲得輸入流。如果Socket還沒有連接,或者已經(jīng)關(guān)閉,或者已經(jīng)通過shutdownInput()方法關(guān)閉輸入流,那么此方法會拋出IOException。ngetOutputStream():獲得輸出流。如果Socket還沒有連接,或者已經(jīng)關(guān)閉,或者已經(jīng)通過shutdownOutput()

22、方法關(guān)閉輸出流,那么此方法會拋出IOException。2.3 關(guān)閉Socketn當(dāng)客戶與服務(wù)器的通信結(jié)束,應(yīng)該及時關(guān)閉Socket,以釋放Socket占用的包括端口在內(nèi)的各種資源。Socket的close()方法負(fù)責(zé)關(guān)閉Socket。Socket socket=null;trysocket=new Socket(,80);/執(zhí)行接收和發(fā)送數(shù)據(jù)的操作catch(IOException e) e.printStackTrace();finally try if(socket!=null)socket.close(); catch(IOException e)

23、e.printStackTrace();2.3 關(guān)閉SocketnSocket類提供了三個狀態(tài)測試方法:nisClosed() nisConnected() nisBound() n如果要判斷一個Socket對象當(dāng)前是否處于連接狀態(tài),可采用以下方式:String isConnected=socket.isConnected() & !socket.isClosed();2.4 半關(guān)閉Socketn有的時候,可能僅僅希望關(guān)閉輸出流或輸入流之一。此時可以采用Socket類提供的半關(guān)閉方法:nshutdownInput():關(guān)閉輸入流。nshutdownOutput(): 關(guān)閉輸出流。2.4 半關(guān)閉

24、Socketn先后調(diào)用Socket的shutdownInput()和shutdownOutput()方法,僅僅關(guān)閉了輸入流和輸出流,并不等價于調(diào)用Socket的close()方法。在通信結(jié)束后,仍然要調(diào)用Socket的close()方法,因為只有該方法才會釋放Socket占用的資源,比如占用的本地端口等。nSocket類還提供了兩個狀態(tài)測試方法,用來判斷輸入流和輸出流是否關(guān)閉:npublic boolean isInputShutdown()npublic boolean isOutputShutdown()2.5 設(shè)置Socket的選項nTCP_NODELAY:表示立即發(fā)送數(shù)據(jù)。nSO_RE

25、SUSEADDR:表示是否允許重用Socket所綁定的本地地址。nSO_TIMEOUT:表示接收數(shù)據(jù)時的等待超時時間。nSO_LINGER:表示當(dāng)執(zhí)行Socket的close()方法時,是否立即關(guān)閉底層的Socket。nSO_SNFBUF:表示發(fā)送數(shù)據(jù)的緩沖區(qū)的大小。nSO_RCVBUF:表示接收數(shù)據(jù)的緩沖區(qū)的大小。nSO_KEEPALIVE:表示對于長時間處于空閑狀態(tài)的Socket,是否要自動把它關(guān)閉。nOOBINLINE:表示是否支持發(fā)送一個字節(jié)的TCP緊急數(shù)據(jù)。2.5.1 TCP_NODELAY選項n設(shè)置該選項:public void setTcpNoDelay(boolean on)

26、throws SocketExceptionn讀取該選項:public boolean getTcpNoDelay() throws SocketExceptionnTCP_NODEALY的默認(rèn)值為false,表示采用Negale算法。如果調(diào)用setTcpNoDelay(true)方法,就會關(guān)閉Socket的緩沖,確保數(shù)據(jù)及時發(fā)送:if(!socket.getTcpNoDelay()socket.setTcpNoDelay(true);n如果Socket的底層實現(xiàn)不支持TCP_NODELAY選項,那么getTcpNoDelay()和setTcpNoDelay()方法會拋出SocketExcep

27、tion。2.5.2 SO_RESUSEADDR選項n設(shè)置該選項:public void setResuseAddress(boolean on) throws SocketExceptionn讀取該選項:public boolean getResuseAddress() throws SocketExceptionn為了確保一個進(jìn)程關(guān)閉了Socket后,即使它還沒釋放端口,同一個主機(jī)上的其他進(jìn)程還可以立刻重用該端口,可以調(diào)用Socket的setResuseAddress(true)方法:if(!socket.getResuseAddress()socket.setResuseAddress(

28、true);n值得注意的是socket.setResuseAddress(true)方法必須在Socket還沒有綁定到一個本地端口之前調(diào)用,否則執(zhí)行socket.setResuseAddress(true)方法無效。2.5.3 SO_TIMEOUT選項n設(shè)置該選項:public void setSoTimeout(int milliseconds) throws SocketExceptionn讀取該選項:public int getSoTimeOut() throws SocketExceptionn當(dāng)通過Socket的輸入流讀數(shù)據(jù)時,如果還沒有數(shù)據(jù),就會等待。例Socket類的SO_TIM

29、EOUT選項用于設(shè)定接收數(shù)據(jù)的等待超時時間,單位為毫秒,它的默認(rèn)值為0,表示會無限等待,永遠(yuǎn)不會超時。2.5.4 SO_LINGER選項n設(shè)置該選項:public void setSoLinger(boolean on, int seconds) throws SocketExceptionn讀取該選項:public int getSoLinger() throws SocketExceptionnSO_LINGER選項用來控制Socket關(guān)閉時的行為。nsocket.setSoLinger(true,0):執(zhí)行Socket的close()方法時,該方法也會立即返回,但底層的Socket也會立

30、即關(guān)閉,所有未發(fā)送完的剩余數(shù)據(jù)被丟棄。nsocket.setSoLinger(true,3600):執(zhí)行Socket的close()方法時,該方法不會立即返回,而進(jìn)入阻塞狀態(tài),同時,底層的Socket會嘗試發(fā)送剩余的數(shù)據(jù)。只有滿足以下兩個條件之一,close()方法才返回:n底層的Socket已經(jīng)發(fā)送完所有的剩余數(shù)據(jù)。n盡管底層的Socket還沒有發(fā)送完所有的剩余數(shù)據(jù),但已經(jīng)阻塞了3600秒。close()方法的阻塞時間超過3600秒,也會返回,剩余未發(fā)送的數(shù)據(jù)被丟棄。2.5.5 SO_RCVBUF選項n設(shè)置該選項:public void setReceiveBufferSize(int si

31、ze) throws SocketExceptionn讀取該選項:public int getReceiveBufferSize() throws SocketExceptionnSO_RCVBUF表示Socket的用于輸入數(shù)據(jù)的緩沖區(qū)的大小。n如果底層Socket不支持SO_RCVBUF選項,那么setReceiveBufferSize()方法會拋出SocketException。2.5.6 SO_SNDBUF選項n設(shè)置該選項:public void setSendBufferSize(int size) throws SocketExceptionn讀取該選項:public int get

32、SendBufferSize() throws SocketExceptionnSO_SNDBUF表示Socket的用于輸出數(shù)據(jù)的緩沖區(qū)的大小。n如果底層Socket不支持SO_SNDBUF選項,setSendBufferSize()方法會拋出SocketException。2.5.7 SO_KEEPALIVE選項n設(shè)置該選項:public void setKeepAlive(boolean on) throws SocketExceptionn讀取該選項:public int getKeepAlive() throws SocketExceptionn當(dāng)SO_KEEPALIVE選項為true

33、,表示底層的TCP實現(xiàn)會監(jiān)視該連接是否有效。nSO_KEEPALIVE選項的默認(rèn)值為false,表示TCP不會監(jiān)視連接是否有效,不活動的客戶端可能會永久存在下去,而不會注意到服務(wù)器已經(jīng)崩潰。2.5.9 服務(wù)類型選項nIP規(guī)定了四種服務(wù)類型,用來定性的描述服務(wù)的質(zhì)量:n低成本:發(fā)送成本低。n高可靠性:保證把數(shù)據(jù)可靠的送達(dá)目的地。n最高吞吐量:一次可以接收或發(fā)送大批量的數(shù)據(jù)。n最小延遲:傳輸數(shù)據(jù)的速度快,把數(shù)據(jù)快速送達(dá)目的地。2.5.9 服務(wù)類型選項n這四種服務(wù)類型還可以進(jìn)行組合,例如,可以同時要求獲得高可靠性和最小延遲。Socket類中提供了設(shè)置和讀取服務(wù)類型的方法:n設(shè)置服務(wù)類型:public void setTrafficClass(int trafficClass) throws SocketExceptionn讀取服務(wù)類型

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論