摘要:?jiǎn)蝹€(gè)請(qǐng)求范圍之外的異常可能會(huì)關(guān)閉服務(wù)器??蛻舳丝赡艹瑫r(shí)或崩潰,用戶可能取消事務(wù),網(wǎng)絡(luò)可能在流量高峰期間癱瘓,黑客可能發(fā)動(dòng)拒絕服務(wù)攻擊。如果默認(rèn)長(zhǎng)度不夠大,一些的構(gòu)造函數(shù)還允許改變這個(gè)隊(duì)列的長(zhǎng)度,不能不能超過(guò)操作系統(tǒng)支持的最大值。
ServerSocket的生命周期
一個(gè)ServerSocket的基本生命周期:
1)使用一個(gè)ServerSocket構(gòu)造函數(shù)在一個(gè)特定端口創(chuàng)建一個(gè)新的ServerSocket
2)ServerSocket使用accept方法監(jiān)聽這個(gè)端口的入站連接,accept方法會(huì)一直阻塞,直到一個(gè)客戶端嘗試建立連接,此時(shí)accept將返回一個(gè)連接客戶端和服務(wù)器的Socket對(duì)象
3)根據(jù)服務(wù)器類型,會(huì)調(diào)用Socket的getInputSteam或getOutputStream方法,或者兩個(gè)方法都調(diào)用,以獲取與客戶端通信的輸入和輸出流
4)服務(wù)器和客戶端根據(jù)已協(xié)商的協(xié)議交互,直到要關(guān)閉連接
5)服務(wù)器或客戶端(或二者)關(guān)閉連接
6)服務(wù)器返回到步驟2,等待下一次連接
有兩類異常,一類異??赡荜P(guān)閉服務(wù)器并記錄一個(gè)錯(cuò)誤信息,另一類異常只關(guān)閉活動(dòng)連接,區(qū)分這兩類異常非常重要。某個(gè)特性連接范圍內(nèi)的異常會(huì)關(guān)閉這個(gè)連接,但是不會(huì)影響其他異?;蛘哧P(guān)閉服務(wù)器。
單個(gè)請(qǐng)求范圍之外的異常可能會(huì)關(guān)閉服務(wù)器。
結(jié)束處理時(shí),一定要關(guān)閉Socket,客戶端不能依賴連接的另一端關(guān)閉Socket,對(duì)于服務(wù)器尤其如此??蛻舳丝赡艹瑫r(shí)或崩潰,用戶可能取消事務(wù),網(wǎng)絡(luò)可能在流量高峰期間癱瘓,黑客可能發(fā)動(dòng)拒絕服務(wù)攻擊。出于諸如此類的眾多原因,你不能依賴于客戶端關(guān)閉Socket,即使協(xié)議有這個(gè)要求也不能完全相信客戶端一定會(huì)關(guān)閉Socket。
請(qǐng)求隊(duì)列操作系統(tǒng)把指向某個(gè)特定端口的入站連接請(qǐng)求存儲(chǔ)在一個(gè)先進(jìn)先出的隊(duì)列中,默認(rèn)地,Java將這個(gè)隊(duì)列的長(zhǎng)度設(shè)置為50,但不同的操作系統(tǒng)會(huì)有所不同。FreeBSD默認(rèn)最大隊(duì)列長(zhǎng)度為128。在這些系統(tǒng)中,Java服務(wù)器socket的隊(duì)列長(zhǎng)度將是操作系統(tǒng)所允許的最大值(小于等于50)。隊(duì)列中填入的未處理連接達(dá)到最大容量時(shí),主機(jī)會(huì)拒絕這個(gè)端口上額外的連接,直到隊(duì)列騰出新的位置出來(lái)為止。很多客戶端在首次連接被拒絕后還會(huì)多次嘗試建立連接。
如果默認(rèn)長(zhǎng)度不夠大,一些ServerSocket的構(gòu)造函數(shù)還允許改變這個(gè)隊(duì)列的長(zhǎng)度,不能不能超過(guò)操作系統(tǒng)支持的最大值。
package network.serversocket; import java.net.*; import java.io.*; import java.util.Date; public class DaytimeServer { public final static int PORT = 13; public static void main(String[] args) { try (ServerSocket server = new ServerSocket(PORT)) { while (true) { try (Socket connection = server.accept()) { Writer out = new OutputStreamWriter(connection.getOutputStream()); Date now = new Date(); out.write(now.toString() +" "); out.flush(); connection.close(); } catch (IOException ex) {} } } catch (IOException ex) { System.err.println(ex); } } }
不管怎樣,我們都希望能夠比新連接到來(lái)的速度更快地清空隊(duì)列。
每個(gè)連接對(duì)應(yīng)一個(gè)線程解決方法是為每個(gè)連接提供它自己的一個(gè)線程,與接入站連接放入隊(duì)列的那個(gè)線程分開。生成一個(gè)線程來(lái)處理每個(gè)入站的連接,這樣可以防止一個(gè)慢客戶端阻塞所有其他客戶端,這種是“每個(gè)連接對(duì)應(yīng)一個(gè)線程”的設(shè)計(jì)。
package network.serversocket; import java.net.*; import java.io.*; import java.util.Date; public class ThreadPerConnectionDemo { public final static int PORT = 13; public static void main(String[] args) { try (ServerSocket server = new ServerSocket(PORT)) { while (true) { try { Socket connection = server.accept(); Thread task = new DaytimeThread(connection); task.start(); } catch (IOException ex) {} } } catch (IOException ex) { System.err.println("Couldn"t start server"); } } private static class DaytimeThread extends Thread { private Socket connection; DaytimeThread(Socket connection) { this.connection = connection; } @Override public void run() { try { Writer out = new OutputStreamWriter(connection.getOutputStream()); Date now = new Date(); out.write(now.toString() +" "); out.flush(); } catch (IOException ex) { System.err.println(ex); } finally { try { connection.close(); } catch (IOException e) { // ignore; } } } } }連接池的版本:
package network.serversocket; import java.io.*; import java.net.*; import java.util.*; import java.util.concurrent.*; public class PooledDaytimeServer { public final static int PORT = 13; public static void main(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(50); try (ServerSocket server = new ServerSocket(PORT)) { while (true) { try { Socket connection = server.accept(); Callable優(yōu)雅地關(guān)閉sockettask = new DaytimeTask(connection); pool.submit(task); } catch (IOException ex) {} } } catch (IOException ex) { System.err.println("Couldn"t start server"); } } private static class DaytimeTask implements Callable { private Socket connection; DaytimeTask(Socket connection) { this.connection = connection; } @Override public Void call() { try { Writer out = new OutputStreamWriter(connection.getOutputStream()); Date now = new Date(); out.write(now.toString() +" "); out.flush(); } catch (IOException ex) { System.err.println(ex); } finally { try { connection.close(); } catch (IOException e) { // ignore; } } return null; } } }
程序員通常會(huì)在一個(gè)try-finally塊中采用close-if-not-null模式了來(lái)關(guān)閉Socket,可以使用無(wú)參構(gòu)造器來(lái)稍加改進(jìn),無(wú)參構(gòu)造器不會(huì)拋出任何異常,也不綁定到一個(gè)端口,因此構(gòu)造放在try外邊,finally里頭直接close。
ServerSocket server = new ServerSocket(); try { SocketAddress address = new InetSocketAddress(port); server.bind(address); // ... work with the server socket } finally { try { server.close(); } catch (IOException ex) { // ignore } }
或者直接采用Java7的AutoCloseable模式:
try (ServerSocket server = new ServerSocket(port)) { // ... work with the server socket }catch (IOException ex) { logger.log(Level.SEVERE, "Could not start server", ex); }
如果要記錄異常信息,可以catch下異常,否則可以不用catch。
要測(cè)試ServerSocket是否打開:
public static boolean isOpen(ServerSocket ss) { return ss.isBound() && !ss.isClosed(); }
isBound方法有歧義,它是表示是否曾經(jīng)綁定到某個(gè)端口,即使它目前已經(jīng)關(guān)閉,isBound仍然會(huì)返回true,因此還需要判斷是否是close。
構(gòu)建ServerSocketServerSocket httpd = new ServerSocket(80, 50);
這里指定了綁定80端口,同時(shí)隊(duì)列一次最多可保存50個(gè)入站連接,如果試圖設(shè)置超過(guò)操作系統(tǒng)的最大隊(duì)列長(zhǎng)度,則會(huì)使用最大隊(duì)列長(zhǎng)度。
ServerSocket server = new ServerSocket(0);
0表示監(jiān)聽未指定的端口,操作系統(tǒng)會(huì)為你選擇可用的端口,稱之為匿名端口。
如果沒有綁定任何端口,則getLocalPort返回-1。
ServerSocket選項(xiàng) 1)SO_TIMEOUT為0的話,表示永不超時(shí),一般服務(wù)端都設(shè)置為永不超時(shí)??蛻舳藙t要指定。
設(shè)置該值必須在調(diào)用accppt之前。
確定是否允許一個(gè)新的Socket綁定到之前使用過(guò)的一個(gè)端口,而此時(shí)可能還有一些發(fā)送到原來(lái)Socket的數(shù)據(jù)正在網(wǎng)絡(luò)上傳輸。
3)SO_RCVBUF設(shè)置了服務(wù)器Socket接受的客戶端Socket默認(rèn)接收緩沖區(qū)的大小。
setReceiveBufferSize來(lái)設(shè)置,必須在accept之前設(shè)置。
為TCP定義了4個(gè)通用的業(yè)務(wù)流模型:
A、低成本
B、高可靠性
C、最大吞吐量
D、最小延遲
可以使用setPerformancePreferences方法描述
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65945.html
SSL,Secure Sockets Layer,安全Socket層TLS,Transport Layer Security,傳輸層安全協(xié)議 package network.secure; import java.io.*; import javax.net.ssl.*; public class HTTPSClient { public static void main(Strin...
摘要:上,數(shù)據(jù)按有限大小的包傳輸,這些包成為數(shù)據(jù)報(bào),每個(gè)數(shù)據(jù)報(bào)包含一個(gè)首部和一個(gè)有效載荷。不過(guò),由于數(shù)據(jù)報(bào)長(zhǎng)度有限,通常必須將數(shù)據(jù)分解為多個(gè)包,再在目的地重新組合。這兩個(gè)構(gòu)造函數(shù),在返回之前會(huì)與遠(yuǎn)程主機(jī)建立一個(gè)活動(dòng)的網(wǎng)絡(luò)連接。 Internet上,數(shù)據(jù)按有限大小的包傳輸,這些包成為數(shù)據(jù)報(bào)(datagram),每個(gè)數(shù)據(jù)報(bào)包含一個(gè)首部(header)和一個(gè)有效載荷(payload)。首部包含包發(fā)...
閱讀 5160·2023-04-25 19:30
閱讀 2187·2023-04-25 15:09
閱讀 2634·2021-11-16 11:45
閱讀 2193·2021-11-15 18:07
閱讀 1473·2021-11-11 17:22
閱讀 2133·2021-11-04 16:06
閱讀 3589·2021-10-20 13:47
閱讀 3051·2021-09-22 16:03