掌握 Java 網路程式設計的第一步,就是理解 ServerSocket 與 Socket 的基本配合。本例去除所有併發、協議解析、異常重試等干擾,只保留核心流程:伺服器監聽 → 客戶端連線 → 雙向收發一條訊息 → 關閉連線。適合初學者建立最直觀的心智模型。
public static void main(String[] args) {
int port = 8888;
ServerSocket mySocket = new ServerSocket(port); // 1. 綁定埠口監聽
Socket sk = mySocket.accept(); // 2. 阻塞等待客戶端連線
BufferedReader in = new BufferedReader(new InputStreamReader(sk.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sk.getOutputStream())), true);
System.out.println("客戶端訊息: " + in.readLine()); // 3. 讀取客戶端訊息
out.println("你好,我是伺服器。埠號:" + port); // 4. 發送回應
// 隱含:main 結束,JVM 關閉 Socket (教學簡化,實戰需显式 close)
}
public static void main(String[] args) {
InetAddress addr = InetAddress.getByName(null); // 本機 IP
Socket sk = new Socket(addr, 8888); // 1. 連線伺服器
BufferedReader in = new BufferedReader(new InputStreamReader(sk.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sk.getOutputStream())), true);
out.println("你好!"); // 2. 發送訊息
System.out.println(in.readLine()); // 3. 讀取伺服器回應
}
ServerSocket(int port):建立伺服器監聽 Socket,綁定指定埠。accept():阻塞直到有客戶端連線,返回新的 Socket 代表此連線。Socket(InetAddress host, int port):客戶端主動發起 TCP 連線。getInputStream()/getOutputStream():取得雙向通訊的位元組流。InputStreamReader / OutputStreamWriter:位元組流轉字元流(指定 charset 避免亂碼)。BufferedReader.readLine() / PrintWriter.println():按行讀寫,自動處理換行符。| 誤區 | 後果 | 正確做法 |
|---|---|---|
忽略 flush() 或 autoFlush=true | 資料停留在緩衝區,對端收不到 | new PrintWriter(out, true) 或手動 flush() |
| 未指定編碼使用預設編碼 | 跨平台/中文環境亂碼 | 明確指定 StandardCharsets.UTF_8 |
| 只處理單一連線 | 無法服務多用戶 | 循環 accept() + 執行緒池/NIO |
| 不關閉資源 | 檔案描述符洩漏,端口佔用 | try-with-resources 或 finally 關閉 |
假設 readLine() 非阻塞 | 無資料時永久卡住 | 設定 SO_TIMEOUT 或使用 NIO 非阻塞 |
sk.setSoTimeout(5000),客戶端斷網時伺服器能拋出 SocketTimeoutException 而非無限等待。new ObjectOutputStream(sk.getOutputStream()).writeObject(obj),伺服器對應反序列化。ServerSocketChannel + Selector 實現單執行緒多路複用。