亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

是否可以在同一端口上創建多個(SSL)ServerSocket?

是否可以在同一端口上創建多個(SSL)ServerSocket?

心有法竹 2023-04-19 10:31:10
public class ServerThread implements Runnable {    private static final int port = 10000;    @Override    public void run() {        ServerSocket serverSocket = new ServerSocket(port);        while (true) {            Socket clientSocket = serverSocket.accept();            ClientThread clientThread = new ClientThread(clientSocket);            // handle the client request in a separate thread        }    }}如果我有 10 個不同的線程運行 ServerThread.run(),這會起作用嗎?或者我應該為所有線程使用相同的 ServerSocket 對象嗎?文檔說:ServerSocket 的構造函數在無法監聽指定端口時拋出異常(例如,該端口已被使用)您可能想知道為什么我首先要這樣做,而不是簡單地讓一個線程運行 ServerSocket.accept()。好吧,我的假設是(如果我錯了請糾正我)accept() 方法可能需要一些時間才能完成建立連接,特別是如果 ServerSocket 是 SSL(因為握手)。所以如果兩個客戶端同時想要連接,一個必須等待另一個。這對于高流量服務器來說是非常糟糕的。更新:似乎 accept() 方法將在屬于隊列的連接建立后立即返回。這意味著如果有一排客戶端等待連接,服務器線程可以以最快的方式處理請求并且只需要一個線程。(除了為每個請求創建一個新線程并啟動線程所花費的時間,但使用線程池時該時間可以忽略不計)ServerSocket 還有一個名為“backlog”的參數,您可以在其中設置隊列中的最大連接數。根據《Java 基礎網絡》一書 3.3.3TCP 本身可以在接受連接方面領先于 TCP 服務器應用程序。它維護一個連接到偵聽套接字的“積壓隊列”,TCP 本身已完成但尚未被應用程序接受。這個隊列存在于底層 TCP 實現和創建監聽套接字的服務器進程之間。預完成連接的目的是加快連接階段,但隊列的長度是有限的,以免預先形成太多與服務器的連接,這些服務器由于任何原因不以相同的速率接受它們。當接收到傳入連接請求且積壓隊列未滿時,TCP 完成連接協議并將連接添加到積壓隊列。此時,客戶端應用程序已完全連接,但服務器應用程序尚未收到連接作為 ServerSocket.accept 的結果值。當它這樣做時,該條目將從隊列中刪除。我仍然不確定在 SSL 的情況下,握手是否也由 ServerSocket.accept() 并行完成以進行同時連接。更新 2 ServerSocket.accept() 方法本身根本不做任何真正的網絡。一旦操作系統建立了新的 TCP 連接,它就會返回。操作系統本身持有一個等待 TCP 連接的隊列,可以通過 ServerSocket 構造函數中的“backlog”參數來控制:ServerSocket serverSocket = new ServerSocket(port, 50); //this will create a server socket with a maximum of 50 connections in the queueSSL 握手在客戶端調用 Socket.connect()之后完成。因此,一個 ServerSocket.accept() 線程就足夠了。
查看完整描述

1 回答

?
慕標5832272

TA貢獻1966條經驗 獲得超4個贊

以下是關于您的問題的一些想法:

您不能listen()在同一個 IP+端口上使用多個ServerSocket.?如果可以,操作系統會將 SYN 數據包傳輸到哪個套接字?*

TCP 確實維護了預先接受的連接的積壓,因此調用將accept()(幾乎)立即返回積壓隊列中的第一個(最舊的)套接字。它通過自動發送 SYN-ACK 數據包來回復客戶端發送的 SYN,并等待回復 ACK(3 次握手)來實現。但是,正如@zero298 所建議的那樣,盡可能快地接受連接通常不是問題。問題將是處理與您將接受的所有套接字的通信所產生的負載,這很可能會使您的服務器崩潰(這實際上是一次 DoS 攻擊)。實際上這個參數通常在這里 太多并發連接在積壓隊列中等待太久backlogaccept()在到達您的應用程序之前,ed 將被 TCP 丟棄。

我建議您使用ExecutorService線程池來運行某個最大數量的線程,而不是為每個客戶端套接字創建一個線程,每個線程處理與一個客戶端的通信。這允許系統資源的優雅降級,而不是創建數百萬個線程,這反過來會導致線程饑餓、內存問題、文件描述符限制……再加上精心選擇的積壓值,您將能夠獲得您的服務器在不崩潰的情況下可以提供的最大吞吐量。run()如果您擔心 SSL 上的 DoS,您的客戶端線程方法應該做的第一件事就是調用startHandshake()新連接的套接字。

關于 SSL 部分,TCP 本身不能做任何 SSL 預接受,因為它需要執行加密/解碼、與密鑰庫對話等,這遠遠超出了它的規范。請注意,在這種情況下您還應該使用SSLServerSocket

積壓隊列用于 TCP 堆棧已完成但尚未被應用程序接受的連接。與 SSL 無關。JSSE 不會進行任何協商,直到您在已接受的套接字上執行一些 I/O,或在其上調用 startHandshake(),這兩者都將在處理連接的線程中執行。我看不出如何利用它制造 DOS 漏洞,至少不是特定于 SSL 的漏洞。如果您遇到 DOS 情況,很可能您正在 accept() 線程中執行本應在連接處理線程中完成的 I/O。

*:雖然Linux >=3.9 做了某種負載平衡,但僅適用于 UDP(所以不是?SSLServerSocket并且有選項SO_REUSEPORT,這并不是在所有平臺上都可用。


查看完整回答
反對 回復 2023-04-19
  • 1 回答
  • 0 關注
  • 157 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號