Socket 是網路通訊的基礎抽象。無論你開發即時聊天、微服務 RPC、物聯網裝置通訊,底層都離不開 Socket。Java 在 java.net 封裝了平台差異,讓開發者專注於應用層協定設計,而非纏繞於作業系統底層的 bind/listen/epoll 細節。本系列將從概念模型、API 實戰、多執行緒/連線池進階、實戰案例四個維度循序漸進。
| OSI 七層 | TCP/IP 四層 | 典型協定/技術 | Socket 位置 |
|---|---|---|---|
| 7. 應用層 | 應用層 | HTTP, FTP, SMTP, DNS | ⬆ 應用程式邏輯 |
| 6. 表達層 | 加密/壓縮/序列化 (SSL, JSON, Protobuf) | ||
| 5. 會話層 | 會話管理 (RPC 框架、WebSocket 握手) | ||
| 4. 傳輸層 | 傳輸層 | TCP, UDP | 🔌 Socket API 介面 |
| 3. 網路層 | 網路層 | IP, ICMP, 路由 | ⬇ 作業系統核心協定棧 |
| 2. 資料鏈路層 | 資料鏈路層 | Ethernet, Wi-Fi, MAC | |
| 1. 實體層 | (合併) | 光纖、銅纜、電波 |
結論:Socket 位於會話層/傳輸層交界,向上為應用提供「可靠位元組流 (TCP)」或「不可靠資料報 (UDP)」的統一介面,向下屏蔽 IP 封包分片、重組、流控、重傳等複雜性。
「Socket 就像電話插座。你的程式是電話機,想跟遠端通話,必須插上插座 (建立 Socket)、撥號 (connect/bind)、建立專線 (TCP 連線)。通話過程中,你只管說話/聽聲音 (read/write),不需知道聲音如何轉為電訊號、經由交換機路由到對方。掛斷 (close) 後,線路釋放。」
InputStream/OutputStream,像讀寫檔案一樣自然。| 特性 | TCP Socket (Socket/ServerSocket) | UDP Socket (DatagramSocket) |
|---|---|---|
| 連線導向 | 是 (三次交握、四次揮手) | 無 (無連線) |
| 可靠性 | 保證有序、不重複、不丟失 | 不保證 (可能丟包、亂序、重複) |
| 流量控制/擁塞控制 | 內建 (滑動窗口、慢啟動) | 無 (應用層自行實作) |
| 資料邊界 | 無 (位元組流,需自行分幀) | 有 (每個 DatagramPacket 保留邊界) |
| 適用場景 | Web、資料庫、訊息隊列、檔案傳輸、SSH | 即時音視訊、DNS、SNMP、遊戲狀態同步、廣播/多播 |
| Java 核心類 | Socket, ServerSocket | DatagramSocket, DatagramPacket |
try (ServerSocket server = new ServerSocket(8080)) {
System.out.println("Server listening on 8080...");
while (true) {
try (Socket client = server.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
PrintWriter out = new PrintWriter(new OutputStreamWriter(client.getOutputStream(), StandardCharsets.UTF_8), true)) {
String msg = in.readLine();
System.out.println("Received: " + msg);
out.println("Echo: " + msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
try (Socket socket = new Socket("localhost", 8080);
PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {
System.out.println("Connected. Type 'bye' to exit.");
String line;
while ((line = console.readLine()) != null) {
out.println(line);
System.out.println("Server: " + in.readLine());
if ("bye".equalsIgnoreCase(line)) break;
}
}
下一篇將深入實戰:多執行緒伺服器架構 (Thread-per-Connection vs Thread Pool)、非阻塞 NIO 入門 (Selector, Channel, Buffer)、連線池與 Keep-Alive 管理、自訂協定編解碼 (Length-Prefix, Delimiter, Protobuf)。