摘要:單個請求范圍之外的異??赡軙P(guān)閉服務(wù)器??蛻舳丝赡艹瑫r或崩潰,用戶可能取消事務(wù),網(wǎng)絡(luò)可能在流量高峰期間癱瘓,黑客可能發(fā)動拒絕服務(wù)攻擊。如果默認長度不夠大,一些的構(gòu)造函數(shù)還允許改變這個隊列的長度,不能不能超過操作系統(tǒng)支持的最大值。
ServerSocket的生命周期
一個ServerSocket的基本生命周期:
1)使用一個ServerSocket構(gòu)造函數(shù)在一個特定端口創(chuàng)建一個新的ServerSocket
2)ServerSocket使用accept方法監(jiān)聽這個端口的入站連接,accept方法會一直阻塞,直到一個客戶端嘗試建立連接,此時accept將返回一個連接客戶端和服務(wù)器的Socket對象
3)根據(jù)服務(wù)器類型,會調(diào)用Socket的getInputSteam或getOutputStream方法,或者兩個方法都調(diào)用,以獲取與客戶端通信的輸入和輸出流
4)服務(wù)器和客戶端根據(jù)已協(xié)商的協(xié)議交互,直到要關(guān)閉連接
5)服務(wù)器或客戶端(或二者)關(guān)閉連接
6)服務(wù)器返回到步驟2,等待下一次連接
有兩類異常,一類異??赡荜P(guān)閉服務(wù)器并記錄一個錯誤信息,另一類異常只關(guān)閉活動連接,區(qū)分這兩類異常非常重要。某個特性連接范圍內(nèi)的異常會關(guān)閉這個連接,但是不會影響其他異?;蛘哧P(guān)閉服務(wù)器。
單個請求范圍之外的異??赡軙P(guān)閉服務(wù)器。
結(jié)束處理時,一定要關(guān)閉Socket,客戶端不能依賴連接的另一端關(guān)閉Socket,對于服務(wù)器尤其如此??蛻舳丝赡艹瑫r或崩潰,用戶可能取消事務(wù),網(wǎng)絡(luò)可能在流量高峰期間癱瘓,黑客可能發(fā)動拒絕服務(wù)攻擊。出于諸如此類的眾多原因,你不能依賴于客戶端關(guān)閉Socket,即使協(xié)議有這個要求也不能完全相信客戶端一定會關(guān)閉Socket。
請求隊列操作系統(tǒng)把指向某個特定端口的入站連接請求存儲在一個先進先出的隊列中,默認地,Java將這個隊列的長度設(shè)置為50,但不同的操作系統(tǒng)會有所不同。FreeBSD默認最大隊列長度為128。在這些系統(tǒng)中,Java服務(wù)器socket的隊列長度將是操作系統(tǒng)所允許的最大值(小于等于50)。隊列中填入的未處理連接達到最大容量時,主機會拒絕這個端口上額外的連接,直到隊列騰出新的位置出來為止。很多客戶端在首次連接被拒絕后還會多次嘗試建立連接。
如果默認長度不夠大,一些ServerSocket的構(gòu)造函數(shù)還允許改變這個隊列的長度,不能不能超過操作系統(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); } } }
不管怎樣,我們都希望能夠比新連接到來的速度更快地清空隊列。
每個連接對應(yīng)一個線程解決方法是為每個連接提供它自己的一個線程,與接入站連接放入隊列的那個線程分開。生成一個線程來處理每個入站的連接,這樣可以防止一個慢客戶端阻塞所有其他客戶端,這種是“每個連接對應(yīng)一個線程”的設(shè)計。
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; } } }
程序員通常會在一個try-finally塊中采用close-if-not-null模式了來關(guān)閉Socket,可以使用無參構(gòu)造器來稍加改進,無參構(gòu)造器不會拋出任何異常,也不綁定到一個端口,因此構(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。
要測試ServerSocket是否打開:
public static boolean isOpen(ServerSocket ss) { return ss.isBound() && !ss.isClosed(); }
isBound方法有歧義,它是表示是否曾經(jīng)綁定到某個端口,即使它目前已經(jīng)關(guān)閉,isBound仍然會返回true,因此還需要判斷是否是close。
構(gòu)建ServerSocketServerSocket httpd = new ServerSocket(80, 50);
這里指定了綁定80端口,同時隊列一次最多可保存50個入站連接,如果試圖設(shè)置超過操作系統(tǒng)的最大隊列長度,則會使用最大隊列長度。
ServerSocket server = new ServerSocket(0);
0表示監(jiān)聽未指定的端口,操作系統(tǒng)會為你選擇可用的端口,稱之為匿名端口。
如果沒有綁定任何端口,則getLocalPort返回-1。
ServerSocket選項 1)SO_TIMEOUT為0的話,表示永不超時,一般服務(wù)端都設(shè)置為永不超時??蛻舳藙t要指定。
設(shè)置該值必須在調(diào)用accppt之前。
確定是否允許一個新的Socket綁定到之前使用過的一個端口,而此時可能還有一些發(fā)送到原來Socket的數(shù)據(jù)正在網(wǎng)絡(luò)上傳輸。
3)SO_RCVBUF設(shè)置了服務(wù)器Socket接受的客戶端Socket默認接收緩沖區(qū)的大小。
setReceiveBufferSize來設(shè)置,必須在accept之前設(shè)置。
為TCP定義了4個通用的業(yè)務(wù)流模型:
A、低成本
B、高可靠性
C、最大吞吐量
D、最小延遲
可以使用setPerformancePreferences方法描述
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.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ù)報,每個數(shù)據(jù)報包含一個首部和一個有效載荷。不過,由于數(shù)據(jù)報長度有限,通常必須將數(shù)據(jù)分解為多個包,再在目的地重新組合。這兩個構(gòu)造函數(shù),在返回之前會與遠程主機建立一個活動的網(wǎng)絡(luò)連接。 Internet上,數(shù)據(jù)按有限大小的包傳輸,這些包成為數(shù)據(jù)報(datagram),每個數(shù)據(jù)報包含一個首部(header)和一個有效載荷(payload)。首部包含包發(fā)...
閱讀 5400·2023-04-25 19:30
閱讀 2260·2023-04-25 15:09
閱讀 2697·2021-11-16 11:45
閱讀 2275·2021-11-15 18:07
閱讀 1526·2021-11-11 17:22
閱讀 2188·2021-11-04 16:06
閱讀 3640·2021-10-20 13:47
閱讀 3090·2021-09-22 16:03