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

Java 網路程式設計實戰:TCP/UDP Socket 核心差異、代碼範例與多執行緒擴展指南

     編輯:Java 相關知識

Socket 是網路程式設計核心抽象。Java 提供 java.net.Socket (TCP) 與 DatagramSocket (UDP) 兩套 API。本文對比兩大協定特性,提供完整客戶端/伺服端代碼範例,並指導多執行緒併發擴展與 GUI 整合方向。

TCP vs UDP 核心差異

特性TCP (Socket)UDP (DatagramSocket)
協定全名Transmission Control ProtocolUser Datagram Protocol
連線模式面向連線 (三次交握)無連線
可靠性保證送達、有序、無重複不保證送達、順序、可能重複
流量控制滑動視窗、阻塞控制無
資料界限位元組流 (無訊息邊界)資料報 (保留訊息邊界)
開銷較大 (標頭 20+ bytes)較小 (標頭 8 bytes)
適用場景檔案傳輸、Web、郵件、資料庫串流媒體、即時遊戲、DNS、SNMP
Java 核心類Socket, ServerSocketDatagramSocket, DatagramPacket

TCP 範例:回聲伺服器與客戶端

伺服端


public class TcpEchoServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(2000)) {
            System.out.println("TCP Server listening on port 2000...");
            while (true) {
                try (Socket client = server.accept();
                     BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
                     PrintWriter out = new PrintWriter(client.getOutputStream(), true)) {
                    
                    String line;
                    while ((line = in.readLine()) != null) {
                        System.out.println("Received: " + line);
                        out.println("Echo: " + line); // 回傳
                    }
                } catch (IOException e) {
                    System.err.println("Client error: " + e.getMessage());
                }
            }
        }
    }
}

客戶端


public class TcpEchoClient {
    public static void main(String[] args) throws IOException {
        try (Socket socket = new Socket("localhost", 2000);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {
            
            String userInput;
            while ((userInput = stdIn.readLine()) != null) {
                out.println(userInput);
                System.out.println("Server: " + in.readLine());
            }
        }
    }
}

UDP 範例:資料報發送與接收

發送端


public class UdpSender {
    public static void main(String[] args) throws IOException {
        if (args.length < 3) {
            System.err.println("Usage: java UdpSender    [-f file]");
            return;
        }
        
        InetAddress address = InetAddress.getByName(args[0]);
        int port = Integer.parseInt(args[1]);
        byte[] data;
        
        if ("-f".equals(args[2])) {
            // 讀取檔案
            Path path = Paths.get(args[3]);
            data = Files.readAllBytes(path);
        } else {
            // 合併剩餘參數為訊息
            String msg = String.join(" ", Arrays.copyOfRange(args, 2, args.length));
            data = msg.getBytes(StandardCharsets.UTF_8);
        }
        
        try (DatagramSocket socket = new DatagramSocket()) {
            DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
            socket.send(packet);
            System.out.println("Sent " + data.length + " bytes to " + address + ":" + port);
        }
    }
}

接收端


public class UdpReceiver {
    public static void main(String[] args) throws IOException {
        if (args.length != 1) {
            System.err.println("Usage: java UdpReceiver ");
            return;
        }
        
        int port = Integer.parseInt(args[0]);
        byte[] buffer = new byte[2048];
        
        try (DatagramSocket socket = new DatagramSocket(port)) {
            System.out.println("UDP Receiver listening on port " + port);
            while (true) {
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet); // 阻塞等待
                
                String msg = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
                System.out.println(packet.getAddress().getHostAddress() + ": " + msg);
                
                // 重設長度供下次複用 (Java 1.1+ 必須)
                packet.setLength(buffer.length);
            }
        }
    }
}

關鍵技術細節

  1. UDP 緩衝區大小:buffer.length 限制單次接收上限,超截資料將丟失。大檔案需分片或改用 TCP
  2. DatagramPacket.setLength():複用 Packet 前必須重設長度,否則後續接收會被截斷
  3. TCP 訊息邊界:readLine() 依賴換行符;二進位協議需自定義長度前綴或分隔符
  4. 資源管理:try-with-resources 確保 Socket/Stream 正確關閉

多執行緒併發擴展:TCP 伺服端模板


public class ConcurrentTcpServer {
    private static final ExecutorService pool = Executors.newCachedThreadPool();
    
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(2000)) {
            System.out.println("Concurrent TCP Server started...");
            while (true) {
                Socket client = server.accept();
                pool.submit(() -> handleClient(client));
            }
        } finally {
            pool.shutdown();
        }
    }
    
    private static void handleClient(Socket client) {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
             PrintWriter out = new PrintWriter(client.getOutputStream(), true)) {
            
            String line;
            while ((line = in.readLine()) != null) {
                out.println("Thread-" + Thread.currentThread().getId() + ": " + line);
            }
        } catch (IOException e) {
            System.err.println("Client handler error: " + e.getMessage());
        }
    }
}

GUI 整合方向:Swing/JavaFX 聊天室原型

  • 客戶端:JTextArea 顯示訊息、JTextField 輸入、背景執行緒接收伺服端推送
  • 伺服端:維護 Set<PrintWriter> 廣播訊息給所有連線客戶端
  • 關鍵點:Swing 單執行緒規則 → SwingUtilities.invokeLater() 更新 UI

生產級增強清單

  1. 連線/閒置超時設定:socket.setSoTimeout()
  2. SSL/TLS 加密:SSLSocketFactory / SSLServerSocketFactory
  3. 訊息協議框架:Netty、Mina、gRPC 替代裸 Socket
  4. 服務發現與負載均衡:Nacos、Consul、Kubernetes Service
  5. 監控指標:連線數、QPS、延遲分位、錯誤率 (Micrometer + Prometheus)
  6. 優雅關閉:訊號處理、執行緒池關閉、進行中請求完成

掌握 TCP/UDP Socket 基礎,是理解 HTTP、RPC、微服務通訊底層原理的關鍵。從裸 Socket 起步,逐步引入成熟框架,能建立扎實的網路程式設計功力。

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