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

Java Socket 編程實戰(一):TCP 回聲服務端與客戶端基礎實現

     編輯:Java 相關知識

前言

TCP(Transmission Control Protocol)提供面向連接、可靠、有序的字節流服務,是絕大多數業務協議(HTTP、MySQL、Redis、Dubbo...)的傳輸基石。本文給出最小化的 TCP Echo 服務端與客戶端實現,解析 ServerSocket/Socket 核心流程,並指出單線程模型局限。

一、核心類職責

類角色關鍵方法
ServerSocket服務端監聽套接字accept() 阻塞等待客戶端連接,返回 Socket
Socket雙端通信端點getInputStream()/getOutputStream()、close()
InetAddressIP 地址封裝getByName(host)、getHostAddress()

二、服務端:單線程 Echo

public class TCPEchoServer {
    private static final int BUFSIZE = 32;
    public static void main(String[] args) throws IOException {
        ServerSocket servSock = new ServerSocket(5500);
        byte[] recvBuf = new byte[BUFSIZE];
        while (true) {
            Socket clntSock = servSock.accept();           // 阻塞等待連接
            System.out.println("Client: " + clntSock.getRemoteSocketAddress());
            try (InputStream in = clntSock.getInputStream();
                 OutputStream out = clntSock.getOutputStream()) {
                int recvMsgSize;
                while ((recvMsgSize = in.read(recvBuf)) != -1) { // 讀到流末尾 -1
                    out.write(recvBuf, 0, recvMsgSize);         // 原樣回寫
                }
            } // try-with-resources 自動關閉流與 Socket
        }
    }
}

2.1 關鍵流程

  1. new ServerSocket(port):綁定端口,進入 LISTEN 狀態。
  2. accept():阻塞直到三次握手完成,返回已連接 Socket。
  3. 獲取流:InputStream 讀取客戶端數據,OutputStream 發送響應。
  4. read() 返回 -1 表示客戶端關閉輸出流(發送 FIN),服務端隨後關閉連接。

三、客戶端:發送並驗證回聲

public class TCPEchoClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 5500);
        byte[] data = "Hi, World".getBytes();
        try (OutputStream out = socket.getOutputStream();
             InputStream in = socket.getInputStream()) {
            out.write(data);                              // 發送
            out.flush();                                  // 確保發送
            
            int total = 0, recv;
            while (total < data.length) {                 // 確保讀滿預期長度
                recv = in.read(data, total, data.length - total);
                if (recv == -1) throw new SocketException("Server closed prematurely");
                total += recv;
            }
            System.out.println("Received: " + new String(data));
        }
    }
}

3.1 關鍵細節

  • TCP 粘包/拆包:read() 可能分多次返回,必須循環讀滿預期長度或用分隔符/長度前綴協議幀解碼。
  • flush():刷新發送緩衝區,減少 Nagle 算法延遲(關鍵交互建議 setTcpNoDelay(true))。
  • 異常處理:read() 返回 -1 非異常,屬正常關閉流程;連接重置拋 SocketException。

四、單線程模型局限與擴展路線

局限後果演進方向
串行 accept/處理併發能力 = 1,延遲隨排隊線性增長線程池:ExecutorService 提交任務;或 CompletableFuture
阻塞 IO線程數 = 連接數,C10K 問題NIO 選擇器:Selector + 非阻塞 SocketChannel;或 Netty 事件循環
無協議幀粘包導致業務解析錯誤定義協議:長度前綴 / 分隔符 / 固定長度;Netty LengthFieldBasedFrameDecoder
無優雅關閉強制關閉導致數據丟失關閉鉤子 + 空閒檢測 + 協議層心跳

五、生產級 TCP 服務端架構草圖

Boss Group (1)          Worker Group (N)
   │                         │
   ▼                         ▼
ServerSocketChannel    Selector Loop
   │                         │
   ├── accept() ──────────► │
   │                        ├── register(OP_READ)
   │                        ├── read() → decode → business → encode → write()
   │                        └── close() on error/idle

這正是 Netty「主從 Reactor 多線程模型」的核心思想。

六、總結

TCP 編程入口雖簡單(ServerSocket/Socket + 流),但可靠傳輸 ≠ 簡單業務:粘包拆包、背壓流控、連接生命周期、優雅關閉、TLS 加密、協議設計,每一項都是深水區。掌握阻塞 IO 基礎模型,是理解 NIO、Netty、gRPC 等高性能框架的必經之路。

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