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

Java TCP/UDP 網絡通信編程完整指南:從基礎 API 到生產級服務端模型

     編輯:Java 相關知識

Java 提供 java.net 包原生支援 TCP/UDP 通信。本文系統講解:InetAddress 地址封裝、DatagramSocket/UDP 無連接通信、ServerSocket/Socket TCP 面向連接通信、多線程/線程池服務端模型、NIO 非阻塞演進方向,附帶可直接運行的完整代碼範例。

基礎知識速查

  • 回環地址:127.0.0.1 / ::1 (IPv6),本機內部通信,無需網卡
  • 端口範圍:0-65535,0-1023 為知名端口 (需特權),應用建議用 1024+
  • 協議選擇:TCP 可靠有序 (Web、DB、RPC);UDP 低延遲無連接 (DNS、流媒體、心跳、廣播)

UDP 通信:DatagramSocket + DatagramPacket

核心類速覽

類關鍵構造/方法用途
DatagramSocketnew DatagramSocket() / new DatagramSocket(port) / send(p) / receive(p)發送/接收數據報,綁定本地端口
DatagramPacketnew DatagramPacket(buf, len) (接收) / new DatagramPacket(buf, len, addr, port) (發送)數據報容器,攜帶數據、地址、端口
InetAddressgetByName(host) / getLocalHost() / getHostAddress()IP 地址封裝

UDP 發送端

public class UdpSender {
    public static void main(String[] args) throws IOException {
        try (DatagramSocket socket = new DatagramSocket()) {
            String msg = "Hello UDP @ " + Instant.now();
            byte[] data = msg.getBytes(StandardCharsets.UTF_8);
            InetAddress target = InetAddress.getByName("192.168.1.100");
            int port = 9000;
            DatagramPacket packet = new DatagramPacket(data, data.length, target, port);
            socket.send(packet);
            System.out.println("已發送: " + msg);
        }
    }
}

UDP 接收端

public class UdpReceiver {
    public static void main(String[] args) throws IOException {
        try (DatagramSocket socket = new DatagramSocket(9000)) {
            byte[] buffer = new byte[4096];
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            System.out.println("UDP 接收端就緒,端口 9000...");
            while (true) {
                socket.receive(packet); // 阻塞等待
                String msg = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
                System.out.printf("收自 %s:%d → %s%n", 
                    packet.getAddress().getHostAddress(), packet.getPort(), msg);
                packet.setLength(buffer.length); // 重置長度,供下次接收
            }
        }
    }
}

TCP 通信:ServerSocket + Socket

核心類速覽

類關鍵構造/方法用途
ServerSocketnew ServerSocket(port) / accept() → 返回新 Socket服務端監聽,accept() 阻塞直到客戶端連接
Socketnew Socket(host, port) / getInputStream() / getOutputStream()客戶端發起連接,雙向流通信

TCP 服務端:單線程版 (教學用)

public class TcpServerSimple {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(8080)) {
            System.out.println("TCP 服務端啟動,端口 8080");
            while (true) {
                try (Socket client = server.accept();
                     BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
                     PrintWriter out = new PrintWriter(new OutputStreamWriter(client.getOutputStream(), StandardCharsets.UTF_8), true)) {
                    
                    System.out.println("客戶端連接: " + client.getInetAddress());
                    String line;
                    while ((line = in.readLine()) != null) {
                        System.out.println("收到: " + line);
                        out.println("Echo: " + line); // 自動 flush
                        if ("quit".equalsIgnoreCase(line)) break;
                    }
                } catch (IOException e) {
                    System.err.println("客戶端通信異常: " + e.getMessage());
                }
            }
        }
    }
}

TCP 服務端:多線程版 (生產雛形)

public class TcpServerThreadPool {
    private static final ExecutorService POOL = Executors.newFixedThreadPool(50);

    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(8080)) {
            System.out.println("TCP 服務端啟動 (線程池), 端口 8080");
            while (true) {
                Socket client = server.accept();
                POOL.submit(() -> handleClient(client));
            }
        }
    }

    private static void handleClient(Socket client) {
        String clientInfo = client.getInetAddress() + ":" + client.getPort();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
             PrintWriter out = new PrintWriter(new OutputStreamWriter(client.getOutputStream(), StandardCharsets.UTF_8), true)) {
            
            System.out.println("處理客戶端: " + clientInfo);
            String line;
            while ((line = in.readLine()) != null) {
                String response = processRequest(line); // 業務邏輯
                out.println(response);
                if ("quit".equalsIgnoreCase(line)) break;
            }
        } catch (IOException e) {
            System.err.println("客戶端 " + clientInfo + " 異常: " + e.getMessage());
        } finally {
            try { client.close(); } catch (IOException ignored) {}
        }
    }

    private static String processRequest(String req) {
        // 實際業務:解析協議、調用服務、返回結果
        return "Server processed: " + req;
    }
}

TCP 客戶端

public class TcpClient {
    public static void main(String[] args) throws IOException {
        String host = args.length > 0 ? args[0] : "127.0.0.1";
        int port = args.length > 1 ? Integer.parseInt(args[1]) : 8080;

        try (Socket socket = new Socket(host, port);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
             PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
             BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
            
            System.out.println("已連接至 " + host + ":" + port);
            String line;
            while ((line = keyboard.readLine()) != null) {
                out.println(line);
                String response = in.readLine();
                if (response == null) break;
                System.out.println("服務端: " + response);
                if ("quit".equalsIgnoreCase(line)) break;
            }
        }
    }
}

進階主題:從 BIO 到 NIO

模型特點適用場景Java API
BIO (阻塞)每連接一線程,簡單但擴展性差連接數 < 1000,低併發ServerSocket/Socket
NIO (非阻塞)單線程管理多連接,Selector 輪詢就緒事件高併發、長連接 (IM、推送)ServerSocketChannel, Selector
AIO (異步)內核完成 I/O 後回調,真正異步超高併發、大文件傳輸AsynchronousServerSocketChannel
NettyNIO 封裝框架,事件驅動、管道、零拷貝、內存池生產首選:高性能、穩定、生態豐富netty-all

關鍵最佳實踐

  1. 顯式指定編碼:StandardCharsets.UTF_8,杜絕亂碼
  2. try-with-resources:保證 Socket/流關閉,防洩漏
  3. 線程池隔離:業務處理提交線程池,accept 線程專職接受連接
  4. 協議分幀:TCP 字節流需應用層定義邊界 (長度前綴/分隔符/序列化)
  5. 心跳/超時:長連接必須有空閒檢測機制
  6. 優雅關閉:關閉 ServerSocket 觸發 accept 異常 → 關閉線程池 → 等待任務完成

總結

Java 原生 TCP/UDP API 簡潔強大,掌握 ServerSocket/Socket 與 DatagramSocket/DatagramPacket 核心類、多線程服務端模型、編碼與資源管理最佳實踐,即可構建健壯網絡應用。高併發場景建議直接使用 Netty,站在巨人肩膀上專注業務邏輯。

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