單線程 accept() → 處理完整會話 → 再 accept(),同一時刻只能服務一個客戶端,後續連接排隊阻塞。
public class TcpServer {
private static final int PORT = 12345;
private static final ExecutorService POOL = Executors.newFixedThreadPool(50);
public static void main(String[] args) throws IOException {
try (ServerSocket server = new ServerSocket(PORT)) {
System.out.println("Server started on " + PORT);
while (true) {
Socket client = server.accept(); // 阻塞等待新連接
POOL.submit(new ClientHandler(client)); // 交給線程池異步處理
}
}
}
static class ClientHandler implements Runnable {
private final Socket socket;
ClientHandler(Socket socket) { this.socket = socket; }
@Override public void run() {
try (socket;
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream()) {
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) != -1) {
// 業務邏輯:反轉字節順序
byte[] resp = new byte[len];
for (int i = 0; i < len; i++) resp[i] = buf[len - 1 - i];
out.write(resp, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class TcpClient {
public static void main(String[] args) {
String[] msgs = {"abc", "def", "ghi", "jkl", "mno"};
for (String msg : msgs) {
new Thread(() -> {
try (Socket s = new Socket("localhost", 12345);
OutputStream out = s.getOutputStream();
InputStream in = s.getInputStream()) {
out.write(msg.getBytes());
out.flush();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println("Sent: " + msg + " → Recv: " + new String(buf, 0, len));
} catch (IOException e) { e.printStackTrace(); }
}).start();
}
}
}
| 點 | 說明 |
|---|---|
| ServerSocket 單例 | 全程只需一個 ServerSocket 監聽固定端口 |
| accept() 返回新 Socket | 每個客戶端連接對應一個獨立 Socket,互不干擾 |
| 線程池隔離 | Executors.newFixedThreadPool 避免無限創建線程 OOM |
| try-with-resources | 確保 Socket/流異常時也能關閉,防止句柄洩漏 |
| 業務邏輯無狀態 | Handler 不共享可變狀態,天然線程安全 |
連接數超過 1 萬時,線程池模型受限於線程上下文切換,建議遷移 Netty:EventLoopGroup + ChannelPipeline 實現高併發低延遲。