Java網(wǎng)絡編程精解chapter3_第1頁
Java網(wǎng)絡編程精解chapter3_第2頁
Java網(wǎng)絡編程精解chapter3_第3頁
Java網(wǎng)絡編程精解chapter3_第4頁
Java網(wǎng)絡編程精解chapter3_第5頁
已閱讀5頁,還剩24頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、Java網(wǎng)絡編程精解第3章 ServerSocket用法詳解 參考Java網(wǎng)絡編程精解的第3章n3.1 構造ServerSocketn3.2 接收和關閉與客戶的連接n3.3 關閉ServerSocketn3.4 獲取ServerSocket的信息n3.5 ServerSocket選項n3.6 創(chuàng)建多線程的服務器n3.7 關閉服務器3.1 構造ServerSocketnServerSocket的構造方法有以下幾種重載形式:n(1)ServerSocket()throws IOException n(2)ServerSocket(int port) throws IOException n(3)S

2、erverSocket(int port, int backlog) throws IOExceptionn(4)ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException 3.1.1 綁定端口ServerSocket serverSocket=new ServerSocket(80);n如果運行時無法綁定到80端口,以上代碼會拋出IOException,更確切的說,是拋出BindException,它是IOException的子類。nBindException一般是由以下原因造成的:n端口已經(jīng)被其他

3、服務器進程占用。n在某些操作系統(tǒng)中,如果沒有以超級用戶的身份來運行服務器程序,那么操作系統(tǒng)不允許服務器綁定到11023之間的端口。3.1.2 設定客戶連接請求隊列的長度 serverSocket = new ServerSocket(port,3); /連接請求隊列的長度為3nServerSocket構造方法的backlog參數(shù)用來顯式設置連接請求隊列的長度,它將覆蓋操作系統(tǒng)限定的隊列的最大長度。n值得注意的是,在以下幾種情況,仍然會采用操作系統(tǒng)限定的隊列的最大長度:nbacklog參數(shù)的值大于操作系統(tǒng)限定的隊列的最大長度。nbacklog參數(shù)的值小于或等于0。n在ServerSocket構造

4、方法中沒有設置backlog參數(shù)。3.1.3 設定綁定的IP地址nserverSocket=new ServerSocket(8000,10,InetAddress.getByName();n如果主機只有一個IP地址,那么默認情況下,服務器程序就與該IP地址綁定。nServerSocket的第四個構造方法ServerSocket(int port, int backlog, InetAddress bindAddr)有一個bindAddr參數(shù),它顯式指定服務器要綁定的IP地址,該構造方法適用于具有多個IP地址的主機。3.1.4 默認構造方法的作用n通過該方法創(chuàng)建的Serv

5、erSocket不與任何端口綁定,接下來還需要通過bind()方法與特定端口綁定。n在以下代碼中,先把ServerSocket的SO_REUSEADDR選項設為true,然后再把它與8000端口綁定:ServerSocket serverSocket=new ServerSocket();serverSocket.setReuseAddress(true); /設置ServerSocket的選項serverSocket.bind(new InetSocketAddress(8000); /與8000端口綁定3.2 接收和關閉與客戶的連接public void service() /單線程服務器

6、采用的通信流程 while (true) Socket socket=null; try socket = serverSocket.accept(); /從連接請求隊列中取出一個連接 System.out.println(New connection accepted + socket.getInetAddress() + : +socket.getPort(); /接收和發(fā)送數(shù)據(jù) catch (IOException e) /這只是與單個客戶通信時遇到的異常,可能是由于客戶端過早斷開連接引起的 /這種異常不應該中斷整個while循環(huán) e.printStackTrace(); finally

7、 try if(socket!=null)socket.close(); /與一個客戶通信結束后,要關閉Socket catch (IOException e) e.printStackTrace(); 3.3 關閉ServerSocketn以下程序代碼創(chuàng)建了一個ServerSocket對象后,就馬上關閉它,以便及時釋放它占用的端口,從而避免程序臨時占用系統(tǒng)的大多數(shù)端口。for(int port=1;port=65535;port+) try ServerSocket serverSocket=new ServerSocket(port); serverSocket.close(); /及時關

8、閉ServerSocket catch(IOException e) System.out.println(端口+port+ 已經(jīng)被其他服務器進程占用); 3.4 獲取ServerSocket的信息nServerSocket的以下兩個get方法分別獲得服務器綁定的IP地址,以及綁定的端口:npublic InetAddress getInetAddress()npublic int getLocalPort()3.5 ServerSocket選項nSO_TIMEOUT:表示等待客戶連接的超時時間。nSO_REUSEADDR:表示是否允許重用服務器所綁定的地址。nSO_RCVBUF:表示接收數(shù)據(jù)

9、的緩沖區(qū)的大小。3.5.1 SO_TIMEOUT選項n設置該選項:public void setSoTimeout(int timeout) throws SocketExceptionn讀取該選項:public int getSoTimeout () throws IOExceptionnSO_TIMEOUT表示ServerSocket的accept()方法等待客戶連接的超時時間,以毫秒為單位。如果SO_TIMEOUT的值為0,表示永遠不會超時,這是SO_TIMEOUT的默認值。n當服務器執(zhí)行ServerSocket的accept()方法時,如果連接請求隊列為空,服務器就會一直等待,直到接收

10、到了客戶連接才從accept()方法返回。如果設定了超時時間,那么當服務器等待的時間超過了超時時間,就會拋出SocketTimeoutException,它是InterruptedException的子類。3.5.2 SO_REUSEADDR選項n設置該選項:public void setResuseAddress(boolean on) throws SocketExceptionn讀取該選項:public boolean getResuseAddress() throws SocketExceptionn這個選項與Socket的SO_REUSEADDR選項相同,用于決定如果網(wǎng)絡上仍然有數(shù)據(jù)

11、向舊的ServerSocket傳輸,是否允許新的ServerSocket綁定到與舊的ServerSocket同樣的端口。n為了確保一個進程關閉了ServerSocket后,即使操作系統(tǒng)還沒釋放端口,同一個主機上的其他進程還可以立刻重用該端口,可以調(diào)用ServerSocket的setResuseAddress(true)方法。n值得注意的是,serverSocket.setResuseAddress(true)方法必須在ServerSocket還沒有綁定到一個本地端口之前調(diào)用,否則執(zhí)行serverSocket.setResuseAddress(true)方法無效。 3.5.3 SO_RCVBUF

12、選項n設置該選項:public void setReceiveBufferSize(int size) throws SocketExceptionn讀取該選項:public int getReceiveBufferSize() throws SocketExceptionnSO_RCVBUF表示服務器端的用于接收數(shù)據(jù)的緩沖區(qū)的大小,以字節(jié)為單位。一般說來,傳輸大的連續(xù)的數(shù)據(jù)塊(比如基于HTTP或FTP協(xié)議的數(shù)據(jù)傳輸)可以使用較大的緩沖區(qū),這可以減少傳輸數(shù)據(jù)的次數(shù),從而提高傳輸數(shù)據(jù)的效率。而對于交互式的通信(比如Telnet和網(wǎng)絡游戲),則應該采用小的緩沖區(qū),確保能及時把小批量的數(shù)據(jù)發(fā)送給對方

13、。n執(zhí)行serverSocket.setReceiveBufferSize()方法,相當于對所有由serverSocket.accept()方法返回的Socket設置接收數(shù)據(jù)的緩沖區(qū)的大小。3.5.4 設定連接時間、延遲和帶寬的相對重要性npublic void setPerformancePreferences(int connectionTime,int latency,int bandwidth)n該方法的作用與Socket的setPerformancePreferences()方法的作用相同,用于設定連接時間、延遲和帶寬的相對重要性。3.6 創(chuàng)建多線程的服務器n可以用并發(fā)性能來衡量一個

14、服務器同時響應多個客戶的能力。一個具有好的并發(fā)性能的服務器,必須符合兩個條件:n能同時接收并處理多個客戶連接。n對于每個客戶,都會迅速給予響應。n服務器同時處理的客戶連接數(shù)目越多,并且對每個客戶做出響應的速度越快,就表明并發(fā)性能越高。3.6 創(chuàng)建多線程的服務器n用多個線程來同時為多個客戶提供服務,這是提高服務器的并發(fā)性能的最常用的手段。本節(jié)將按照三種方式來重新實現(xiàn)EchoServer,它們都使用了多線程:n方式一:為每個客戶分配一個工作線程。n方式二:創(chuàng)建一個線程池,由其中的工作線程來為客戶服務。n方式三:利用JDK的Java類庫中現(xiàn)成的線程池,由它的工作線程來為客戶服務。3.6.1 為每個客

15、戶分配一個線程n服務器的主線程負責接收客戶的連接,每次接收到一個客戶連接,就會創(chuàng)建一個工作線程,由它負責與客戶的通信。以下是EchoServer的service()方法的代碼:public void service() while (true) Socket socket=null; try socket = serverSocket.accept(); /接收客戶連接 Thread workThread=new Thread(new Handler(socket); /創(chuàng)建一個工作線程 workThread.start(); /啟動工作線程 catch (IOException e) e.p

16、rintStackTrace(); 3.6.2 創(chuàng)建線程池n線程池為線程生命周期開銷問題和系統(tǒng)資源不足問題提供了解決方案。線程池中預先創(chuàng)建了一些工作線程,它們不斷從工作隊列中取出任務,然后執(zhí)行該任務。當工作線程執(zhí)行完一個任務,就會繼續(xù)執(zhí)行工作隊列中的下一個任務。n線程池具有以下優(yōu)點:n減少了創(chuàng)建和銷毀線程的次數(shù),每個工作線程都可以一直被重用,能執(zhí)行多個任務。n可以根據(jù)系統(tǒng)的承載能力,方便的調(diào)整線程池中線程的數(shù)目,防止因為消耗過量系統(tǒng)資源而導致系統(tǒng)崩潰。n參見ThreadPool類3.6.3 使用JDK類庫提供的線程池njava.util.concurrent包提供了現(xiàn)成的線程池的實現(xiàn)。Exec

17、utor接口表示線程池,它的execute(Runnable task)方法用來執(zhí)行Runnable類型的任務。Executor的子接口ExecutorService中聲明了管理線程池的一些方法,比如用于關閉線程池的shutdown()方法等。Executors類中包含一些靜態(tài)方法,它們負責生成各種類型的線程池ExecutorService實例。3.6.3 使用JDK類庫提供的線程池3.6.3 使用JDK類庫提供的線程池nEchoServer就利用上述線程池來負責與客戶通信的任務。 public EchoServer() throws IOException serverSocket = ne

18、w ServerSocket(port); /創(chuàng)建線程池 /Runtime的availableProcessors()方法返回當前系統(tǒng)的CPU的數(shù)目 /系統(tǒng)的CPU越多,線程池中工作線程的數(shù)目也越多 executorService= Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() * POOL_SIZE); System.out.println(服務器啟動); 3.6.4 使用線程池的注意事項n線程池可能會帶來種種風險:n1死鎖n2系統(tǒng)資源不足n3并發(fā)錯誤n4線程泄漏n5任務過載3.6.4 使用線程池的注意事項n使用線程池時需要遵循以下原則:n(1)如果任務A在執(zhí)行過程中需要同步等待任務B的執(zhí)行結果,那么任務A不適合加入到線程池的工作隊列中。n(2)如果執(zhí)行某個任務時可能會阻塞,并且是長時間的阻塞,則應該設定超時時間,避免工作線程永久的阻塞下去而導致線程泄漏。n(3)根據(jù)任務的特點,對任務進行分類,然后把不同類型的任務分別加入到不同線程池的工作隊列中,這樣可以根據(jù)任務的特點,分別調(diào)整每個線程池。n(4)調(diào)整

溫馨提示

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

評論

0/150

提交評論