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

Java 網絡編程核心:ServerSocket 深度解析與配置優化

     編輯:Java 相關知識

ServerSocket 是 Java BIO 模型下服務端監聽連接的核心類。掌握其構造器、常用方法、Socket 選項配置,是構建高性能、穩定網絡服務的基礎。本文系統梳理四種構造器差異、核心 API、四大關鍵 Socket 選項及最佳實踐。

一、四種構造器對比

構造器參數含義適用場景異常
ServerSocket()無參,創建未綁定 Socket需先設置選項(如 reuseAddress)再綁定端口IOException
ServerSocket(int port)綁定指定端口,backlog 默認 50快速啟動,單實例服務BindException (端口占用)
ServerSocket(int port, int backlog)指定端口 + 接受隊列長度高併發連接突發場景,調大 backlogBindException
ServerSocket(int port, int backlog, InetAddress bindAddr)指定端口、backlog、綁定 IP多網卡服務器,綁定內網/外網特定 IPBindException

backlog 參數深度:內核維護兩個隊列:
1. 未完成連接隊列(SYN_RCVD 狀態)
2. 已完成連接隊列(ESTABLISHED,等待 accept() 取走)
backlog 歷史上指已完成隊列大小,Linux 2.2+ 為兩隊列之和。高併發建議設置 1024 或更大,並同步調內核參數 net.core.somaxconn。

二、核心查詢方法

public InetAddress getInetAddress()   // 返回綁定的本地 IP(多網卡時確認生效 IP)
public int getLocalPort()             // 返回綁定端口(0 表示系統自動分配時獲取實際端口)

三、四大 Socket 選項詳解(必須在 bind 前設置)

1. SO_TIMEOUT — 接受超時

public void setSoTimeout(int timeout)   // 毫秒,0 表示永不超時
public int getSoTimeout()
  • 作用於 accept() 阻塞等待時間。
  • 超時拋出 SocketTimeoutException,可用於實現優雅關閉輪詢:while(!shutdown) { try { socket = server.accept(); } catch (SocketTimeoutException e) { /* 檢查 shutdown 標誌 */ } }

2. SO_REUSEADDR — 端口複用

public void setReuseAddress(boolean on)
public boolean getReuseAddress()
  • 關鍵場景:服務重啟時,前一次佔用端口處於 TIME_WAIT 狀態(默認 60s),開啟此選項允許立即重綁定。
  • 必須在 bind() 前調用,否則無效。
  • 對應內核 SO_REUSEADDR,不同於 SO_REUSEPORT(Linux 3.9+,多線程負載均衡)。

3. SO_RCVBUF — 接收緩衝區大小

public void setReceiveBufferSize(int size)  // 字節
public int getReceiveBufferSize()
  • 影響內核為該 Socket 分配的接收緩衝區上限。
  • 默認值由 net.core.rmem_default 決定(通常 128KB~256KB)。
  • 設置值 > 64KB 時必須在 bind 前調用;否則 bind 後調用無效。
  • 實際值由內核雙倍並受 net.core.rmem_max 限制,調用 getReceiveBufferSize() 可查看生效值。

4. 性能偏好設置(Java 7+)

public void setPerformancePreferences(int connectionTime, int latency, int bandwidth)
  • 提示 JVM 優化方向:連接建立速度、延遲、帶吞吐量,權重相對值。
  • 實際效果依賴 JVM 實現與底層協議棧,通常作為微調手段。

四、完整服務端啟動模板

public class ServerBootstrap {
    public static void main(String[] args) throws IOException {
        int port = 8080;
        ServerSocket server = new ServerSocket(); // 1. 未綁定
        
        // 2. 設置選項(bind 前)
        server.setReuseAddress(true);
        server.setReceiveBufferSize(256 * 1024); // 256KB
        server.setSoTimeout(3000);               // 3s 輪詢關閉標誌
        
        // 3. 綁定端口
        server.bind(new InetSocketAddress(port), 1024); // backlog=1024
        System.out.println("Server listening on " + server.getLocalPort());
        
        // 4. 接受循環
        volatile boolean running = true;
        Runtime.getRuntime().addShutdownHook(new Thread(() -> running = false));
        
        try {
            while (running) {
                try {
                    Socket client = server.accept();
                    // 提交線程池處理,避免阻塞 accept
                    executor.submit(() -> handle(client));
                } catch (SocketTimeoutException ignored) {
                    // 定期檢查 running 標誌
                }
            }
        } finally {
            server.close();
            executor.shutdown();
        }
    }
}

五、從 BIO 到 NIO 的演進提示

ServerSocket 屬於阻塞 IO(BIO),每連接一線程,C10K 問題明顯。生產環境高併發建議遷移至:

  • NIO:ServerSocketChannel + Selector,單線程多路複用。
  • Netty:事件驅動框架,封裝 NIO 細節,提供編解碼、心跳、SSL、流控等企業級特性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved