版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Java網(wǎng)絡(luò)編程精解第3章 ServerSocket用法詳解 參考Java網(wǎng)絡(luò)編程精解的第3章n3.1 構(gòu)造ServerSocketn3.2 接收和關(guān)閉與客戶(hù)的連接n3.3 關(guān)閉ServerSocketn3.4 獲取ServerSocket的信息n3.5 ServerSocket選項(xiàng)n3.6 創(chuàng)建多線程的服務(wù)器n3.7 關(guān)閉服務(wù)器3.1 構(gòu)造ServerSocketnServerSocket的構(gòu)造方法有以下幾種重載形式: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如果運(yùn)行時(shí)無(wú)法綁定到80端口,以上代碼會(huì)拋出IOException,更確切的說(shuō),是拋出BindException,它是IOException的子類(lèi)。nBindException一般是由以下原因造成的:n端口已經(jīng)被其他
3、服務(wù)器進(jìn)程占用。n在某些操作系統(tǒng)中,如果沒(méi)有以超級(jí)用戶(hù)的身份來(lái)運(yùn)行服務(wù)器程序,那么操作系統(tǒng)不允許服務(wù)器綁定到11023之間的端口。3.1.2 設(shè)定客戶(hù)連接請(qǐng)求隊(duì)列的長(zhǎng)度 serverSocket = new ServerSocket(port,3); /連接請(qǐng)求隊(duì)列的長(zhǎng)度為3nServerSocket構(gòu)造方法的backlog參數(shù)用來(lái)顯式設(shè)置連接請(qǐng)求隊(duì)列的長(zhǎng)度,它將覆蓋操作系統(tǒng)限定的隊(duì)列的最大長(zhǎng)度。n值得注意的是,在以下幾種情況,仍然會(huì)采用操作系統(tǒng)限定的隊(duì)列的最大長(zhǎng)度:nbacklog參數(shù)的值大于操作系統(tǒng)限定的隊(duì)列的最大長(zhǎng)度。nbacklog參數(shù)的值小于或等于0。n在ServerSocket構(gòu)造
4、方法中沒(méi)有設(shè)置backlog參數(shù)。3.1.3 設(shè)定綁定的IP地址nserverSocket=new ServerSocket(8000,10,InetAddress.getByName();n如果主機(jī)只有一個(gè)IP地址,那么默認(rèn)情況下,服務(wù)器程序就與該IP地址綁定。nServerSocket的第四個(gè)構(gòu)造方法ServerSocket(int port, int backlog, InetAddress bindAddr)有一個(gè)bindAddr參數(shù),它顯式指定服務(wù)器要綁定的IP地址,該構(gòu)造方法適用于具有多個(gè)IP地址的主機(jī)。3.1.4 默認(rèn)構(gòu)造方法的作用n通過(guò)該方法創(chuàng)建的Serv
5、erSocket不與任何端口綁定,接下來(lái)還需要通過(guò)bind()方法與特定端口綁定。n在以下代碼中,先把ServerSocket的SO_REUSEADDR選項(xiàng)設(shè)為true,然后再把它與8000端口綁定:ServerSocket serverSocket=new ServerSocket();serverSocket.setReuseAddress(true); /設(shè)置ServerSocket的選項(xiàng)serverSocket.bind(new InetSocketAddress(8000); /與8000端口綁定3.2 接收和關(guān)閉與客戶(hù)的連接public void service() /單線程服務(wù)器
6、采用的通信流程 while (true) Socket socket=null; try socket = serverSocket.accept(); /從連接請(qǐng)求隊(duì)列中取出一個(gè)連接 System.out.println(New connection accepted + socket.getInetAddress() + : +socket.getPort(); /接收和發(fā)送數(shù)據(jù) catch (IOException e) /這只是與單個(gè)客戶(hù)通信時(shí)遇到的異常,可能是由于客戶(hù)端過(guò)早斷開(kāi)連接引起的 /這種異常不應(yīng)該中斷整個(gè)while循環(huán) e.printStackTrace(); finally
7、 try if(socket!=null)socket.close(); /與一個(gè)客戶(hù)通信結(jié)束后,要關(guān)閉Socket catch (IOException e) e.printStackTrace(); 3.3 關(guān)閉ServerSocketn以下程序代碼創(chuàng)建了一個(gè)ServerSocket對(duì)象后,就馬上關(guān)閉它,以便及時(shí)釋放它占用的端口,從而避免程序臨時(shí)占用系統(tǒng)的大多數(shù)端口。for(int port=1;port=65535;port+) try ServerSocket serverSocket=new ServerSocket(port); serverSocket.close(); /及時(shí)關(guān)
8、閉ServerSocket catch(IOException e) System.out.println(端口+port+ 已經(jīng)被其他服務(wù)器進(jìn)程占用); 3.4 獲取ServerSocket的信息nServerSocket的以下兩個(gè)get方法分別獲得服務(wù)器綁定的IP地址,以及綁定的端口:npublic InetAddress getInetAddress()npublic int getLocalPort()3.5 ServerSocket選項(xiàng)nSO_TIMEOUT:表示等待客戶(hù)連接的超時(shí)時(shí)間。nSO_REUSEADDR:表示是否允許重用服務(wù)器所綁定的地址。nSO_RCVBUF:表示接收數(shù)據(jù)
9、的緩沖區(qū)的大小。3.5.1 SO_TIMEOUT選項(xiàng)n設(shè)置該選項(xiàng):public void setSoTimeout(int timeout) throws SocketExceptionn讀取該選項(xiàng):public int getSoTimeout () throws IOExceptionnSO_TIMEOUT表示ServerSocket的accept()方法等待客戶(hù)連接的超時(shí)時(shí)間,以毫秒為單位。如果SO_TIMEOUT的值為0,表示永遠(yuǎn)不會(huì)超時(shí),這是SO_TIMEOUT的默認(rèn)值。n當(dāng)服務(wù)器執(zhí)行ServerSocket的accept()方法時(shí),如果連接請(qǐng)求隊(duì)列為空,服務(wù)器就會(huì)一直等待,直到接收
10、到了客戶(hù)連接才從accept()方法返回。如果設(shè)定了超時(shí)時(shí)間,那么當(dāng)服務(wù)器等待的時(shí)間超過(guò)了超時(shí)時(shí)間,就會(huì)拋出SocketTimeoutException,它是InterruptedException的子類(lèi)。3.5.2 SO_REUSEADDR選項(xiàng)n設(shè)置該選項(xiàng):public void setResuseAddress(boolean on) throws SocketExceptionn讀取該選項(xiàng):public boolean getResuseAddress() throws SocketExceptionn這個(gè)選項(xiàng)與Socket的SO_REUSEADDR選項(xiàng)相同,用于決定如果網(wǎng)絡(luò)上仍然有數(shù)據(jù)
11、向舊的ServerSocket傳輸,是否允許新的ServerSocket綁定到與舊的ServerSocket同樣的端口。n為了確保一個(gè)進(jìn)程關(guān)閉了ServerSocket后,即使操作系統(tǒng)還沒(méi)釋放端口,同一個(gè)主機(jī)上的其他進(jìn)程還可以立刻重用該端口,可以調(diào)用ServerSocket的setResuseAddress(true)方法。n值得注意的是,serverSocket.setResuseAddress(true)方法必須在ServerSocket還沒(méi)有綁定到一個(gè)本地端口之前調(diào)用,否則執(zhí)行serverSocket.setResuseAddress(true)方法無(wú)效。 3.5.3 SO_RCVBUF
12、選項(xiàng)n設(shè)置該選項(xiàng):public void setReceiveBufferSize(int size) throws SocketExceptionn讀取該選項(xiàng):public int getReceiveBufferSize() throws SocketExceptionnSO_RCVBUF表示服務(wù)器端的用于接收數(shù)據(jù)的緩沖區(qū)的大小,以字節(jié)為單位。一般說(shuō)來(lái),傳輸大的連續(xù)的數(shù)據(jù)塊(比如基于HTTP或FTP協(xié)議的數(shù)據(jù)傳輸)可以使用較大的緩沖區(qū),這可以減少傳輸數(shù)據(jù)的次數(shù),從而提高傳輸數(shù)據(jù)的效率。而對(duì)于交互式的通信(比如Telnet和網(wǎng)絡(luò)游戲),則應(yīng)該采用小的緩沖區(qū),確保能及時(shí)把小批量的數(shù)據(jù)發(fā)送給對(duì)方
13、。n執(zhí)行serverSocket.setReceiveBufferSize()方法,相當(dāng)于對(duì)所有由serverSocket.accept()方法返回的Socket設(shè)置接收數(shù)據(jù)的緩沖區(qū)的大小。3.5.4 設(shè)定連接時(shí)間、延遲和帶寬的相對(duì)重要性npublic void setPerformancePreferences(int connectionTime,int latency,int bandwidth)n該方法的作用與Socket的setPerformancePreferences()方法的作用相同,用于設(shè)定連接時(shí)間、延遲和帶寬的相對(duì)重要性。3.6 創(chuàng)建多線程的服務(wù)器n可以用并發(fā)性能來(lái)衡量一個(gè)
14、服務(wù)器同時(shí)響應(yīng)多個(gè)客戶(hù)的能力。一個(gè)具有好的并發(fā)性能的服務(wù)器,必須符合兩個(gè)條件:n能同時(shí)接收并處理多個(gè)客戶(hù)連接。n對(duì)于每個(gè)客戶(hù),都會(huì)迅速給予響應(yīng)。n服務(wù)器同時(shí)處理的客戶(hù)連接數(shù)目越多,并且對(duì)每個(gè)客戶(hù)做出響應(yīng)的速度越快,就表明并發(fā)性能越高。3.6 創(chuàng)建多線程的服務(wù)器n用多個(gè)線程來(lái)同時(shí)為多個(gè)客戶(hù)提供服務(wù),這是提高服務(wù)器的并發(fā)性能的最常用的手段。本節(jié)將按照三種方式來(lái)重新實(shí)現(xiàn)EchoServer,它們都使用了多線程:n方式一:為每個(gè)客戶(hù)分配一個(gè)工作線程。n方式二:創(chuàng)建一個(gè)線程池,由其中的工作線程來(lái)為客戶(hù)服務(wù)。n方式三:利用JDK的Java類(lèi)庫(kù)中現(xiàn)成的線程池,由它的工作線程來(lái)為客戶(hù)服務(wù)。3.6.1 為每個(gè)客
15、戶(hù)分配一個(gè)線程n服務(wù)器的主線程負(fù)責(zé)接收客戶(hù)的連接,每次接收到一個(gè)客戶(hù)連接,就會(huì)創(chuàng)建一個(gè)工作線程,由它負(fù)責(zé)與客戶(hù)的通信。以下是EchoServer的service()方法的代碼:public void service() while (true) Socket socket=null; try socket = serverSocket.accept(); /接收客戶(hù)連接 Thread workThread=new Thread(new Handler(socket); /創(chuàng)建一個(gè)工作線程 workThread.start(); /啟動(dòng)工作線程 catch (IOException e) e.p
16、rintStackTrace(); 3.6.2 創(chuàng)建線程池n線程池為線程生命周期開(kāi)銷(xiāo)問(wèn)題和系統(tǒng)資源不足問(wèn)題提供了解決方案。線程池中預(yù)先創(chuàng)建了一些工作線程,它們不斷從工作隊(duì)列中取出任務(wù),然后執(zhí)行該任務(wù)。當(dāng)工作線程執(zhí)行完一個(gè)任務(wù),就會(huì)繼續(xù)執(zhí)行工作隊(duì)列中的下一個(gè)任務(wù)。n線程池具有以下優(yōu)點(diǎn):n減少了創(chuàng)建和銷(xiāo)毀線程的次數(shù),每個(gè)工作線程都可以一直被重用,能執(zhí)行多個(gè)任務(wù)。n可以根據(jù)系統(tǒng)的承載能力,方便的調(diào)整線程池中線程的數(shù)目,防止因?yàn)橄倪^(guò)量系統(tǒng)資源而導(dǎo)致系統(tǒng)崩潰。n參見(jiàn)ThreadPool類(lèi)3.6.3 使用JDK類(lèi)庫(kù)提供的線程池njava.util.concurrent包提供了現(xiàn)成的線程池的實(shí)現(xiàn)。Exec
17、utor接口表示線程池,它的execute(Runnable task)方法用來(lái)執(zhí)行Runnable類(lèi)型的任務(wù)。Executor的子接口ExecutorService中聲明了管理線程池的一些方法,比如用于關(guān)閉線程池的shutdown()方法等。Executors類(lèi)中包含一些靜態(tài)方法,它們負(fù)責(zé)生成各種類(lèi)型的線程池ExecutorService實(shí)例。3.6.3 使用JDK類(lèi)庫(kù)提供的線程池3.6.3 使用JDK類(lèi)庫(kù)提供的線程池nEchoServer就利用上述線程池來(lái)負(fù)責(zé)與客戶(hù)通信的任務(wù)。 public EchoServer() throws IOException serverSocket = ne
18、w ServerSocket(port); /創(chuàng)建線程池 /Runtime的availableProcessors()方法返回當(dāng)前系統(tǒng)的CPU的數(shù)目 /系統(tǒng)的CPU越多,線程池中工作線程的數(shù)目也越多 executorService= Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() * POOL_SIZE); System.out.println(服務(wù)器啟動(dòng)); 3.6.4 使用線程池的注意事項(xiàng)n線程池可能會(huì)帶來(lái)種種風(fēng)險(xiǎn):n1死鎖n2系統(tǒng)資源不足n3并發(fā)錯(cuò)誤n4線程泄漏n5任務(wù)過(guò)載3.6.4 使用線程池的注意事項(xiàng)n使用線程池時(shí)需要遵循以下原則:n(1)如果任務(wù)A在執(zhí)行過(guò)程中需要同步等待任務(wù)B的執(zhí)行結(jié)果,那么任務(wù)A不適合加入到線程池的工作隊(duì)列中。n(2)如果執(zhí)行某個(gè)任務(wù)時(shí)可能會(huì)阻塞,并且是長(zhǎng)時(shí)間的阻塞,則應(yīng)該設(shè)定超時(shí)時(shí)間,避免工作線程永久的阻塞下去而導(dǎo)致線程泄漏。n(3)根據(jù)任務(wù)的特點(diǎn),對(duì)任務(wù)進(jìn)行分類(lèi),然后把不同類(lèi)型的任務(wù)分別加入到不同線程池的工作隊(duì)列中,這樣可以根據(jù)任務(wù)的特點(diǎn),分別調(diào)整每個(gè)線程池。n(4)調(diào)整
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 全新公司合同擔(dān)保協(xié)議下載
- 借貸居間合同
- 食品檢測(cè)服務(wù)合同
- 吊車(chē)施工合同
- 個(gè)人借款給企業(yè)的合同范文
- 污水處理廠運(yùn)維合同履約承諾書(shū)
- 基于線性材料插值的超彈性結(jié)構(gòu)拓?fù)鋬?yōu)化方法研究
- 多參量智能光纖傳感系統(tǒng)研究
- 列車(chē)軸裝通風(fēng)式制動(dòng)盤(pán)流量特性的數(shù)值研究
- 開(kāi)放世界中的目標(biāo)感知與多任務(wù)決策方法研究
- 高考模擬作文“文化自信:春節(jié)走向世界”導(dǎo)寫(xiě)+范文3篇
- 蘇教版三年級(jí)下冊(cè)數(shù)學(xué)計(jì)算能手1000題帶答案
- 改善護(hù)理服務(wù)行動(dòng)計(jì)劃總結(jié)報(bào)告
- 湖南汽車(chē)工程職業(yè)學(xué)院?jiǎn)握新殬I(yè)技能測(cè)試參考試題庫(kù)(含答案)
- 第2課+古代希臘羅馬(教學(xué)設(shè)計(jì))-【中職專(zhuān)用】《世界歷史》(高教版2023基礎(chǔ)模塊)
- 中儲(chǔ)糧蘭州公司考試筆試題庫(kù)
- 焊接機(jī)器人在汽車(chē)制造中應(yīng)用案例分析報(bào)告
- 重建成長(zhǎng)型思維課件
- 電捕焦油器火災(zāi)爆炸事故分析
- 質(zhì)量問(wèn)題分析及措施報(bào)告
- 汽修廠安全風(fēng)險(xiǎn)分級(jí)管控清單
評(píng)論
0/150
提交評(píng)論