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

Java Socket 編程實戰(二):UDP 通信基礎與超時重傳客戶端

     編輯:Java 相關知識

前言

UDP(User Datagram Protocol)無連接、不可靠、有邊界,適合即時性要求高、容忍丟包場景(視頻流、DNS、遊戲同步)。本文給出完整的 UDP Echo 服務端與帶超時重傳的客戶端實現,並分析單線程模型局限。

一、核心類與區別

TCPUDP
ServerSocket / SocketDatagramSocket(客戶端/服務端通用)
流式 InputStream/OutputStream數據報 DatagramPacket(含數據、地址、端口)
連接建立三次握手無連接,直接發送
保證有序、無重複、無丟失不保證,應用層自行處理

二、服務端:單線程 Echo

public class UDPEchoServer {
    private static final int ECHOMAX = 255;
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(5500);
        DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX);
        while (true) {
            socket.receive(packet);                    // 阻塞等待數據報
            System.out.println("Client: " + packet.getAddress() + ":" + packet.getPort());
            socket.send(packet);                       // 原樣返回
            packet.setLength(ECHOMAX);                 // 重置長度,防止緩衝區收縮
        }
    }
}

關鍵點:packet.setLength(ECHOMAX) 必須在每次 send 後調用,因 receive 會將 length 設置為實際接收長度,下次發送會只發送該長度數據。

三、客戶端:超時重傳邏輯

public class UDPEchoClientTimeout {
    private static final int TIMEOUT = 3000;   // 3 秒超時
    private static final int MAXTRIES = 5;     // 最大重試 5 次
    public static void main(String[] args) throws IOException {
        InetAddress server = InetAddress.getByName("127.0.0.1");
        DatagramSocket socket = new DatagramSocket();
        socket.setSoTimeout(TIMEOUT);          // 設置接收超時

        byte[] data = "Hi, World".getBytes();
        DatagramPacket sendPkt = new DatagramPacket(data, data.length, server, 5500);
        DatagramPacket recvPkt = new DatagramPacket(new byte[data.length], data.length);

        int tries = 0;
        boolean received = false;
        do {
            socket.send(sendPkt);
            try {
                socket.receive(recvPkt);
                if (!recvPkt.getAddress().equals(server)) 
                    throw new IOException("Unknown source");
                received = true;
            } catch (InterruptedIOException e) {
                tries++;
                System.out.println("Timed out, " + (MAXTRIES - tries) + " more tries...");
            }
        } while (!received && tries < MAXTRIES);

        if (received) System.out.println("Received: " + new String(recvPkt.getData()));
        else System.out.println("No response -- giving up.");
        socket.close();
    }
}

3.1 關鍵機制解析

  • socket.setSoTimeout(ms):設置 receive() 阻塞上限,超時拋 InterruptedIOException(SocketTimeoutException 父類)。
  • 冪等性要求:Echo 服務天然冪等,重傳安全。非冪等業務(如扣款)需引入序列號+去重。
  • 指數退避優化:生產環境建議 TIMEOUT *= 2 避免擁塞崩潰。

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

局限影響解決方案
串行處理高併發下請求排隊、延遲飆升線程池 + 工作隊列;或 Netty/UDP NIO 事件循環
無背壓突發流量直接丟包/ OOM應用層限流(Token Bucket)、內核 SO_RCVBUF 調大
無會話識別難以關聯請求響應自定義協議頭加 requestId,客戶端維护映射表

五、UDP 適用場景速查

  • ✅ 視頻/音頻流(丟幀可接受、低延遲優先)
  • ✅ DNS 查詢(小包、請求響應模式)
  • ✅ 即時遊戲狀態同步(位置、動作、延遲敏感)
  • ✅ 日誌/指標上報(允許丟失、發送端無感)
  • ❌ 文件傳輸、支付下單、關鍵業務數據(需可靠傳輸,用 TCP/QUIC)

六、總結

UDP 編程核心是應用層承擔可靠性責任:超時重傳、序列號去重、流控擁塞控制。理解 DatagramSocket/DatagramPacket 雙元組模型,配合 setSoTimeout 實現基礎重傳,是掌握高性能網絡編程的必修課。

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