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

Java 網路程式設計基石:Socket 通訊原理、TCP/UDP 實作與高併發架構模式

     編輯:Java 綜合教學

網路程式設計的兩大核心問題

所有網路通訊本質上解決兩個問題:

  1. 如何唯一標識通訊雙方? → IP 地址 + 端口號 = Socket 地址。
  2. 如何可靠/高效傳輸資料? → 選擇 TCP(可靠串流) 或 UDP(無連線數據報) 協議。

Socket 抽象模型

Socket 是「IP:Port」的程式碼抽象,提供標準 API 供應用層讀寫網路資料流。Java 在 java.net 套件提供兩大類:

  • Socket / ServerSocket — TCP 面向連線。
  • DatagramSocket / DatagramPacket — UDP 無連線。

TCP Socket 經典實作(阻塞 I/O 模型)

伺服器端

public class TcpEchoServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(8888)) {
            System.out.println("Server started on port 8888");
            while (true) {
                Socket client = server.accept(); // 阻塞等待連線
                new Thread(() -> handleClient(client)).start(); // 為每連線開線程
            }
        }
    }

    private static void handleClient(Socket socket) {
        try (socket;
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
             PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true)) {

            String line;
            while ((line = in.readLine()) != null) {
                System.out.println("Received: " + line);
                out.println("Echo: " + line); // 回射
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客戶端

public class TcpEchoClient {
    public static void main(String[] args) throws IOException {
        try (Socket socket = new Socket("localhost", 8888);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
             PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
             BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {

            String input;
            while ((input = console.readLine()) != null) {
                out.println(input);
                System.out.println("Server: " + in.readLine());
            }
        }
    }
}

UDP DatagramSocket 實作

// 伺服器
public class UdpEchoServer {
    public static void main(String[] args) throws IOException {
        try (DatagramSocket socket = new DatagramSocket(9999)) {
            byte[] buf = new byte[1024];
            while (true) {
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                socket.receive(packet); // 阻塞接收
                String msg = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
                System.out.println("From " + packet.getAddress() + ":" + packet.getPort() + " - " + msg);
                // 原路回覆
                socket.send(new DatagramPacket(packet.getData(), packet.getLength(), packet.getAddress(), packet.getPort()));
            }
        }
    }
}

// 客戶端
public class UdpEchoClient {
    public static void main(String[] args) throws IOException {
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress addr = InetAddress.getByName("localhost");
            byte[] buf = "Hello UDP".getBytes(StandardCharsets.UTF_8);
            DatagramPacket packet = new DatagramPacket(buf, buf.length, addr, 9999);
            socket.send(packet);
            // 接收回覆
            byte[] recv = new byte[1024];
            DatagramPacket resp = new DatagramPacket(recv, recv.length);
            socket.receive(resp);
            System.out.println("Server reply: " + new String(resp.getData(), 0, resp.getLength(), StandardCharsets.UTF_8));
        }
    }
}

TCP vs UDP 選型指南

維度TCP (Socket)UDP (DatagramSocket)
連線建立三次握手、有狀態無連線、無狀態
可靠性有序、無重複、無丟失(重傳、ACK)不保證,應用層自行處理
流量控制/擁塞控制滑動窗口、慢啟動、快速恢復無,需應用層實現
延遲較高(握手、確認)極低
適用場景HTTP、RPC、資料庫、檔案傳輸、IM 長連線直播推流、VoIP、遊戲狀態同步、DNS、SNMP

高併發架構演進

  1. BIO (Blocking I/O):一連線一線程(上例),線程數=連線數,C10K 問題。
  2. NIO (New I/O, JDK 1.4):Selector + Channel + Buffer,單線程輪詢多連線,Netty/Mina 基石。
  3. AIO (Asynchronous I/O, JDK 7):AsynchronousSocketChannel + CompletionHandler,Proactor 模式,Windows IOCP 加持。
  4. 虛擬執行緒 (JDK 21+):Thread.startVirtualThread(() -> { blockingSocketCode(); }),以同步阻塞寫法獲得 NIO 級併發,徹底簡化網路程式設計。

虛擬執行緒 TCP 伺服器(JDK 21+ 推薦)

public class VirtualThreadTcpServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(8888)) {
            System.out.println("Virtual Thread Server started");
            while (true) {
                Socket client = server.accept();
                Thread.startVirtualThread(() -> handleClient(client)); // 輕量級虛擬執行緒
            }
        }
    }
    // handleClient 同 BIO 版本,無需修改
}

實戰關鍵點總結

  • 字符編碼:显式指定 StandardCharsets.UTF_8,避免平台預設編碼不一致導致亂碼。
  • 資源關閉:try-with-resources 確保 Socket、流正確關閉,防止句柄洩漏。
  • 半關閉處理:socket.shutdownOutput() 發送 FIN,對端 read() 返回 -1,雙向關閉更優雅。
  • 超時設定:socket.setSoTimeout(ms) 避免讀取無限阻塞;socket.setSoKeepAlive(true) 偵測死連線。
  • 緩衝區調優:socket.setReceiveBufferSize()/setSendBufferSize() 配合 OS net.core.rmem_max 調大,提升大流量吞吐。
  • 安全性:生產環境必須用 SSLSocket/SSLServerSocket (TLS 1.2+),或接入 Netty + OpenSSL。

掌握 Socket 基礎、協議特性與架構演進,並善用 JDK 21 虛擬執行緒,即能輕鬆構建高效穩定的網路應用。

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