首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

Java Socket TCP 通信完整實戰:客戶端發送、服務端接收、異常處理與資源關閉

     編輯:更多程式設計知識

前言

TCP 提供可靠、有序、面向連接的字節流服務。Java java.net.Socket(客戶端)與 ServerSocket(服務端)是阻塞式 I/O (BIO) 基礎。本文提供最小可運行的雙端代碼、關鍵步驟解析、資源管理最佳實踐。

客戶端代碼

public class TcpClient {
    public static void main(String[] args) throws IOException {
        String host = "192.168.1.100";
        int port = 10002;

        try (Socket socket = new Socket(host, port);
             OutputStream out = socket.getOutputStream()) {

            String msg = "TCP 測試:客戶端發送數據";
            out.write(msg.getBytes(StandardCharsets.UTF_8));
            out.flush(); // 確保發送緩衝區刷新
        } // try-with-resources 自動關閉 socket 與流
    }
}

服務端代碼

public class TcpServer {
    public static void main(String[] args) throws IOException {
        int port = 10002;

        try (ServerSocket server = new ServerSocket(port)) {
            System.out.println("服務端啟動,監聽端口 " + port);

            while (true) { // 循環接受多個客戶端
                try (Socket client = server.accept();
                     InputStream in = client.getInputStream()) {

                    String ip = client.getInetAddress().getHostAddress();
                    byte[] buf = new byte[1024];
                    int len = in.read(buf); // 阻塞直到有數據或連接關閉
                    if (len > 0) {
                        String msg = new String(buf, 0, len, StandardCharsets.UTF_8);
                        System.out.printf("%s: %s%n", ip, msg);
                    }
                } catch (IOException e) {
                    System.err.println("客戶端處理異常: " + e.getMessage());
                }
            }
        }
    }
}

關鍵步驟圖解

  1. ServerSocket.bind(port) → 內核分配監聽隊列。
  2. Socket.accept() → 阻塞,直到三次握手完成,返回已連接 Socket。
  3. getInputStream()/getOutputStream() → 獲得雙向字節流管道。
  4. read/write → 應用層協議自定義(定長、分隔符、長度前綴、序列化)。
  5. close() → 發送 FIN,四次揮手關閉連接。

生產級增強清單

  • 線程池處理客戶端:ExecutorService executor = Executors.newCachedThreadPool(); executor.submit(() -> handle(client));
  • 協議幀解碼:使用 LengthFieldBasedFrameDecoder (Netty) 或自寫 readFully 讀取長度前綴。
  • 心跳/空閒檢測:socket.setSoTimeout(ms) 或 Netty IdleStateHandler。
  • 優雅關閉:shutdownOutput() 發送 FIN,繼續讀取對端剩餘數據。
  • SSL/TLS:SSLServerSocketFactory / SSLSocketFactory。

常見坑點

現象原因對策
read() 返回 -1對端關閉輸出流 (EOF)視為連接結束,跳出讀取循環
中文亂碼編碼不一致雙端統一 StandardCharsets.UTF_8
發送大數據卡住發送緩衝區滿分塊發送、檢查 sendBufferSize
端口佔用TIME_WAIT 狀態server.setReuseAddress(true)

總結

BIO 模式下,ServerSocket.accept() 循環 + 線程池處理 + try-with-resources 管理資源 是 Java TCP 服務端的標準模板。理解「流是無邊界字節序列,應用層必須定義協議幀」是避免粘包/半包的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved