架構概覽
- Server:主線程
ServerSocket.accept() 循環,每新連接啟動一個 ClientHandler 線程,廣播消息給所有在線客戶端。
- Client:兩線程——主線程讀取控制台輸入發送;
ReaderThread 循環 socket.getInputStream().read() 打印接收消息。
Server 端
import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer {
private static final int PORT = 8189;
private static final List writers = Collections.synchronizedList(new ArrayList<>());
public static void main(String[] args) throws IOException {
System.out.println("Chat Server started on port " + PORT);
try (ServerSocket listener = new ServerSocket(PORT)) {
while (true) {
new Handler(listener.accept()).start();
}
}
}
private static class Handler extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public Handler(Socket socket) { this.socket = socket; }
@Override public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);
writers.add(out);
String msg;
while ((msg = in.readLine()) != null) {
for (PrintWriter writer : writers) {
writer.println(msg);
}
}
} catch (IOException e) {
System.out.println("Client error: " + e.getMessage());
} finally {
if (out != null) writers.remove(out);
try { socket.close(); } catch (IOException ignored) {}
}
}
}
}
Client 端
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ChatClient {
private static final String HOST = "localhost";
private static final int PORT = 8189;
public static void main(String[] args) throws IOException {
try (Socket socket = new Socket(HOST, PORT);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);
Scanner scanner = new Scanner(System.in)) {
System.out.print("請輸入暱稱: ");
String nickname = scanner.nextLine();
out.println("[" + nickname + "] 加入聊天室");
// 接收線程
new Thread(() -> {
try {
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} catch (IOException ignored) {}
}).start();
// 發送循環
String input;
while (scanner.hasNextLine()) {
input = scanner.nextLine();
if ("/quit".equalsIgnoreCase(input)) break;
out.println("[" + nickname + "] " + input);
}
}
}
}
運行步驟
- 編譯:
javac ChatServer.java ChatClient.java
- 啟動服務端:
java ChatServer
- 多終端啟動客戶端:
java ChatClient
生產級擴展點
- 用
ExecutorService 替代顯式 new Thread,控制並發上限。
- 引入
Protocol(JSON/Protobuf)區分系統消息、私聊、群聊、心跳。
- Netty 重寫:事件驅動、零拷貝、SSL、WebSocket 支持。
- 持久化離線消息、用戶認證、房間管理。