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

Java 多執行緒 Socket 伺服器實作:高併發多連線架構範例

     編輯:Java 相關知識

架構模式:Thread-per-Connection(每連線一執行緒)

經典阻塞 IO (BIO) 模式,主執行緒 ServerSocket.accept() 循環等待連線,每新連線建立一個獨立執行緒處理讀寫。適合連線數較少(<500)、業務邏輯含阻塞操作(資料庫、外部 API)的場景。現代高併發(萬級連線)建議改用 NIO (Netty) 或虛擬執行緒 (Java 21+)。

完整可執行範例

import java.io.*;
import java.net.*;

public class ThreadedEchoServer {

    private static final int PORT = 8000;

    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            serverSocket.setReuseAddress(true); // 避免 TIME_WAIT 導致重啟失敗
            System.out.println("伺服器啟動,監聽埠口: " + PORT);

            while (true) {
                Socket clientSocket = serverSocket.accept(); // 阻塞等待
                // 每個連線派發新執行緒
                new ClientHandler(clientSocket).start();
            }
        } catch (IOException e) {
            System.err.println("伺服器異常: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private static class ClientHandler extends Thread {
        private final Socket clientSocket;

        public ClientHandler(Socket socket) {
            this.clientSocket = socket;
        }

        @Override
        public void run() {
            String clientInfo = clientSocket.getInetAddress() + ":" + clientSocket.getPort();
            System.out.println("新連線: " + clientInfo);

            try (BufferedReader in = new BufferedReader(
                            new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
                 PrintWriter out = new PrintWriter(
                            new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true)) {

                String line;
                while ((line = in.readLine()) != null) {
                    System.out.println("收到 [" + clientInfo + "]: " + line);
                    // 回應邏輯
                    if ("END".equalsIgnoreCase(line.trim())) {
                        out.println("Goodbye!");
                        break;
                    }
                    out.println("Echo: " + line);
                }
            } catch (IOException e) {
                System.err.println("連線異常 [" + clientInfo + "]: " + e.getMessage());
            } finally {
                closeQuietly(clientSocket);
                System.out.println("連線關閉: " + clientInfo);
            }
        }

        private void closeQuietly(Socket socket) {
            if (socket != null) {
                try { socket.close(); } catch (IOException ignored) {}
            }
        }
    }
}

關鍵設計細節解析

環節做法理由
字元編碼明確指定 UTF-8避免平台預設編碼不一致導致亂碼
緩衝讀取BufferedReader.readLine()按行讀取,適配文本協定;二進制請用 InputStream.read()
自動刷新PrintWriter(..., true)println 後自動 flush(),確保即時送達
資源釋放try-with-resources + finally保證 Socket/Stream 關閉,防止檔案描述符洩漏
優雅關閉檢測 "END" 指令主動斷開示範應用層心跳/指令控制
SO_REUSEADDRserverSocket.setReuseAddress(true)重啟時立即復用埠口,開發測試必備

效能瓶頸與擴展方向

Thread-per-Connection 缺點

  • 執行緒開銷大:每連線 ~1MB 棧空間,1000 連線即需 1GB 記憶體。
  • 上下文切換頻繁:大量執行緒競爭 CPU,吞吐量下降。
  • 難以控制總連線數:易遭受連線洪水攻擊耗盡資源。

進階演進路線

  1. 執行緒池:ExecutorService pool = Executors.newFixedThreadPool(200),pool.execute(new ClientHandler(socket)),限制最大並發。
  2. NIO 非阻塞 IO:單執行緒 Selector 多路複用,支援萬級連線(Netty、Mina 框架封裝)。
  3. 虛擬執行緒:Java 21+ Executors.newVirtualThreadPerTaskExecutor(),輕量級執行緒,程式碼幾乎不改即可支援百萬連線。
  4. Reactor/Proactor 模式:事件驅動架構,分離 IO 多路複用與業務處理。

執行緒池改良版片段

import java.util.concurrent.*;

public class PooledThreadServer {
    private static final int PORT = 8000;
    private static final ExecutorService POOL = Executors.newFixedThreadPool(200);

    public static void main(String[] args) {
        try (ServerSocket server = new ServerSocket(PORT)) {
            server.setReuseAddress(true);
            System.out.println("Pooled Server started on " + PORT);
            while (true) {
                Socket client = server.accept();
                POOL.execute(new ClientHandler(client)); // 提交任務而非 new Thread
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            POOL.shutdown();
        }
    }
    // ClientHandler 改實作 Runnable,邏輯同前
}

客戶端測試範例

import java.io.*;
import java.net.*;

public class EchoClient {
    public static void main(String[] args) throws Exception {
        try (Socket socket = new Socket("localhost", 8000);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {

            String input;
            while ((input = console.readLine()) != null) {
                out.println(input);
                String response = in.readLine();
                System.out.println("Server: " + response);
                if ("END".equalsIgnoreCase(input)) break;
            }
        }
    }
}

總結:Thread-per-Connection 是理解 Socket 多併發的基石,教學與中小規模專案足夠。生產環境高併發請直接上 Netty (NIO) 或 Java 21 虛擬執行緒,核心業務邏輯可無縫遷移。

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