public class ChatServer {
private static final int PORT = 8857;
private static final ExecutorService pool = Executors.newCachedThreadPool();
public static void main(String[] args) throws IOException {
try (ServerSocket server = new ServerSocket(PORT)) {
System.out.println("服務器啟動,監聽端口: " + PORT);
while (true) {
Socket client = server.accept();
System.out.println("新連接: " + client.getInetAddress());
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 (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
String msg;
while ((msg = in.readLine()) != null) {
System.out.println("收到: " + msg);
if ("bye".equalsIgnoreCase(msg)) break;
// 廣播給所有客戶端 (簡化:僅回傳確認)
out.println("Server Echo: " + msg);
}
} catch (IOException e) {
System.err.println("客戶端異常斷開: " + e.getMessage());
} finally {
try { socket.close(); } catch (IOException ignored) {}
System.out.println("連接關閉: " + socket.getInetAddress());
}
}
}
}
public class ChatClient {
private static final String HOST = "127.0.0.1";
private static final int PORT = 8857;
public static void main(String[] args) throws IOException {
try (Socket socket = new Socket(HOST, PORT);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {
System.out.println("已連接服務器,輸入 bye 退出");
// 接收線程
Thread receiver = new Thread(() -> {
try {
String line;
while ((line = in.readLine()) != null) {
System.out.println("[Server] " + line);
}
} catch (IOException ignored) {}
});
receiver.setDaemon(true);
receiver.start();
// 主線程發送
String input;
while ((input = console.readLine()) != null) {
out.println(input);
if ("bye".equalsIgnoreCase(input)) break;
}
}
}
}
BufferedReader.readLine() + PrintWriter(autoFlush=true) 實現行協議| 功能 | 技術方案 |
|---|---|
| 用戶身份認證 | 握手階段驗證 Token/JWT,關聯 Session 與 User |
| 私聊/群聊 | 維護 Map<String, PrintWriter> userChannels,消息路由 |
| 心跳保活 | 定時發送 PING,超時未收到 PONG 則關閉連接 |
| 消息持久化 | 接入 Redis Stream / Kafka / MySQL 異步落盤 |
| 高併發優化 | Netty NIO 事件循環替換 BIO 線程模型 |
| SSL 加密 | SSLSocketFactory + 憑證雙向認證 |
socket.setKeepAlive(true) + 應用層心跳基於 ServerSocket/Socket + BIO 線程池 的聊天室,代碼量 < 100 行即可實現雙向通訊。核心模式:服務端接受分發、客戶端雙線程收發、行協議分幀、資源自動關閉。作為網絡編程入門經典,理解其阻塞模型局限(C10K 問題),為後續學習 Netty、gRPC、WebSocket 奠定堅實基礎。