首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java ServerSocket 類深度解析:構造器、Accept 循環、線程池整合與 NIO 遷移路徑

     編輯:Java 相關知識

ServerSocket 核心定位

java.net.ServerSocket 代表 TCP 伺服端監聽端點,綁定本地特定埠口,專責 accept() 接受客戶端連線請求,返回對應的 Socket 物件進行資料交換。單個 ServerSocket 可服務多客戶端,是「連線工廠」。

構造器全景與參數詳解

常見異常:BindException(埠已佔用)、SecurityException(特權埠<1024 無權限)。

核心方法

  • Socket accept():阻塞等待客戶端連線,返回新 Socket。可設 setSoTimeout(ms) 避免永久阻塞。
  • void close():關閉監聽,釋放埠口。
  • InetAddress getInetAddress() / int getLocalPort():查詢綁定資訊。
  • void setSoTimeout(int timeout):設定 accept() 超時,超時拋 SocketTimeoutException。
  • static void setSocketFactory(SocketImplFactory fac):全域自定義 Socket 實現(極少用)。

經典多執行緒伺服器模式


public class ThreadPerClientServer {
    private final ExecutorService pool = Executors.newFixedThreadPool(100);
    
    public void start(int port) {
        try (ServerSocket server = new ServerSocket(port)) {
            server.setSoTimeout(1000); // 定期檢查關閉標誌
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Socket client = server.accept();
                    pool.submit(() -> handleClient(client));
                } catch (SocketTimeoutException ignored) {}
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            pool.shutdown();
        }
    }
    
    private void handleClient(Socket socket) {
        try (socket;
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
            String line;
            while ((line = in.readLine()) != null) {
                out.println("Echo: " + line);
            }
        } catch (IOException e) {
            log.error("Client error", e);
        }
    }
}

線程池優化:固定大小 + 有界隊列 + 拒絕策略


ExecutorService pool = new ThreadPoolExecutor(
    50, 200,                    // core / max
    60L, TimeUnit.SECONDS,      // keepAlive
    new LinkedBlockingQueue<>(1000), // 有界隊列防 OOM
    new ThreadFactoryBuilder().setNameFormat("server-worker-%d").build(),
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略:呼叫執行緒執行,自然限流
);

遷移至 NIO:為何與如何

構造器參數說明適用場景
ServerSocket(int port)port=0 表示 OS 自動分配空閒埠最簡單用法,預設 backlog=50
ServerSocket(int port, int backlog)backlog:內核等待隊列最大長度(未完成三次交握+已完成未 accept)高併發場景調大(如 1024)
ServerSocket(int port, int backlog, InetAddress bindAddr)bindAddr:多網卡/多 IP 機器指定綁定介面;null 綁定所有多介面服務隔離、安全區域綁定
痛點BIO 線程池NIO Reactor
C10K 併發執行緒數線性增長,記憶體/上下文切換崩潰少量執行緒輪詢萬級連線
閒置連線每連線佔一執行緒(即使無資料)無資料無事件,零 CPU 佔用
擴展性受限於作業系統執行緒上限單機輕鬆 50K+,配合多 Reactor 更高

遷移關鍵步驟

  1. ServerSocketChannel.open().configureBlocking(false)
  2. Selector.open() + serverChannel.register(selector, OP_ACCEPT)
  3. 事件迴圈 while(selector.select() > 0) 處理 OP_ACCEPT/OP_READ/OP_WRITE
  4. 引入 ByteBuffer、協議編解碼器、半包處理
  5. 生產建議:直接使用 Netty,避免重複造輪子。

生產級檢查清單

  • [ ] 埠口衝突處理(啟動檢查、優雅降級)
  • [ ] 連線超時:SO_TIMEOUT (accept/read) + 應用層心跳
  • [ ] 緩衝區大小調優:SO_RCVBUF/SO_SNDBUF 配合 BDP
  • [ ] 優雅關閉:攔截 SIGTERM,停止 accept、等待任務完成、關閉線程池、關閉 ServerSocket
  • [ ] 監控指標:活躍連線數、隊列積壓、執行緒池狀態、錯誤率
  • [ ] 安全:TLS (SSLServerSocket)、存取控制、速率限制

總結

ServerSocket 是 Java 阻塞式 TCP 伺服端的基石。理解其構造器參數、accept() 語義、線程池整合模式,是進階掌握 Netty 等高效能框架的前置知識。現代高併發系統應儘早遷移至 NIO/Netty 架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved