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

Java 網絡編程入門:TCP 協議與 Socket 通信實戰詳解

     編輯:Java 相關知識

前言

網絡編程是後端開發的核心技能。Java 在 JDK 中原生提供了對 TCP/UDP 協議的完整支持,其中 TCP(傳輸控制協議)以其可靠、面向連接、字節流特性,成為構建分布式系統、即時通訊、微服務 RPC 的基石。本文從協議基礎、連接建立流程、ServerSocket/Socket API 實戰,帶你快速掌握 Java TCP 編程精髓。

一、TCP 基礎知識

  • 可靠傳輸:序列號、確認應答、重傳機制、流量控制、擁塞控制保證數據無差錯、不丟失、不重複、按序到達。
  • 面向連接:通信雙方必須先建立連接(三次握手),數據傳輸結束後釋放連接(四次揮手)。
  • 字節流服務:應用層交付給 TCP 的數據視為無結構的字節序列,無消息邊界(需自行處理粘包/拆包)。
  • 端點標識:一個 TCP 端點 = {IP地址, 端口}。一個連接由 {本地IP, 本地端口, 遠程IP, 遠程端口} 唯一確定。

二、連接建立流程與 Socket 角色

TCP 編程中,端點抽象為 Socket(套接字)。按角色分為:

  • 被動套接字:服務端 ServerSocket,處於 LISTEN 狀態,調用 accept() 阻塞等待客戶端連接。
  • 主動套接字:客戶端 Socket 發起連接;服務端 accept() 返回的新 Socket 代表具體連接,雙方通過這兩個主動套接字進行全雙工通信。

四步建立連接

  1. 服務端創建 ServerSocket 綁定端口,進入循環 accept()。
  2. 客戶端創建 Socket(host, port),發起三次握手。
  3. 服務端 accept() 返回,創建新 Socket 處理該連接(通常派發線程池)。
  4. 雙方通過 InputStream/OutputStream 進行數據交換。

TCP 連接建立流程圖

三、實戰:多線程阻塞模式 TCP 服務端

示例功能:服務端接收客戶端文本行,轉大寫返回,收到 bye 斷開連接。

public class TcpServer implements Runnable {
    private final ServerSocket serverSocket;

    public TcpServer(int port) throws IOException {
        this.serverSocket = new ServerSocket(port); // 創建被動套接字,綁定端口
    }

    @Override
    public void run() {
        System.out.println("Server started on port " + serverSocket.getLocalPort());
        while (true) {
            try {
                // 1. 阻塞等待客戶端連接
                Socket clientSocket = serverSocket.accept();
                // 2. 派發新線程處理(生產環境建議使用線程池)
                new Thread(new ClientHandler(clientSocket)).start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    static class ClientHandler implements Runnable {
        private final Socket socket;

        ClientHandler(Socket socket) {
            this.socket = Objects.requireNonNull(socket);
        }

        @Override
        public void run() {
            // try-with-resources 確保 Socket 關閉
            try (Socket s = socket;
                 BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), StandardCharsets.UTF_8));
                 PrintWriter out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(), StandardCharsets.UTF_8), true)) {

                String line;
                while ((line = in.readLine()) != null) {
                    if ("bye".equalsIgnoreCase(line)) break;
                    out.println(line.toUpperCase(Locale.ENGLISH)); // 處理並返回
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

關鍵點解析

  • ServerSocket.accept():阻塞直到新連接到達,返回代表該連接的 Socket。
  • 一連接一線程:簡單但高併發下線程開銷大,後續可優化為 NIO/Netty 非阻塞模型。
  • BufferedReader.readLine():按行讀取,依賴換行符 \n 作為邊界(簡易應用層協議)。
  • PrintWriter(..., true):開啟自動刷新,println 後立即發送。

四、實戰:TCP 客戶端

public class TcpClient implements Runnable {
    private final Socket socket;

    public TcpClient(String host, int port) throws IOException {
        this.socket = new Socket(host, port); // 主動發起連接
    }

    @Override
    public void run() {
        try (Socket s = socket;
             PrintWriter out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(), StandardCharsets.UTF_8), true);
             BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), StandardCharsets.UTF_8));
             Console console = System.console()) {

            String line;
            while ((line = console.readLine()) != null) {
                if ("bye".equalsIgnoreCase(line)) break;
                out.println(line);              // 發送
                System.out.println(in.readLine()); // 接收回顯
            }
            out.println("bye"); // 通知服務端關閉
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

五、進階話題預告

阻塞模式雖簡單,但存在 C10K 問題(線程模型限制併發)。JDK 提供了 ServerSocketChannel/SocketChannel 支持非阻塞 I/O (NIO),結合 Selector 可實現單線程處理萬級連接。下一篇將深入講解 ServerSocket 與 Socket 的初始化參數、超時設置、緩衝區調優及 NIO 非阻塞編程模型。

總結

  • TCP 提供可靠字節流,應用層需自定義協議處理粘包(定長、分隔符、長度前綴)。
  • ServerSocket 負責偵聽,Socket 負責通信。
  • 阻塞 I/O + 多線程適合業務簡單、併發中低的場景;高併發必須轉向 NIO/Netty。
  • 始終指定 StandardCharsets.UTF_8 避免編碼亂碼,使用 try-with-resources 保證資源釋放。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved