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

Java 網絡通信深度解析:TCP、UDP、多播與 NIO 實戰指南

     編輯:Java 程式設計入門

前言

網絡通信是現代應用開發的核心基礎。Java 在 java.net 包中提供了豐富的 API,支援 TCP、UDP、多播以及新一代非阻塞 I/O(NIO)。本文將通過完整的代碼示例,系統梳理這四種通信模型的核心機制、進階優化方向及最佳實踐。

一、TCP 可靠流式通信

1. 基礎 Socket 通信模型

TCP 通信基於 Socket(客戶端)與 ServerSocket(服務端)。建立連接後,雙方通過輸入/輸出流進行數據交換。

客戶端實現

public class SimpleTcpClient {
    public static void main(String[] args) throws IOException {
        Socket socket = null;
        BufferedReader in = null;
        PrintWriter out = null;
        BufferedReader console = null;
        try {
            socket = new Socket(InetAddress.getLocalHost(), 5678);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(), true);
            console = new BufferedReader(new InputStreamReader(System.in));

            String line;
            while ((line = console.readLine()) != null) {
                out.println(line);
                if ("end".equals(line)) break;
                System.out.println("Server: " + in.readLine());
            }
        } finally {
            closeQuietly(socket, in, out, console);
        }
    }
}

服務端實現(單線程阻塞)

public class SimpleTcpServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(5678);
             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) {
                out.println("Response: " + line);
                if ("end".equals(line)) break;
            }
        }
    }
}

缺點:單線程模型下,服務端同一時間只能處理一個客戶端請求,吞吐量極低。

2. 多線程並發模型

為每個客戶端連接創建獨立線程,實現並發處理。

public class SmartTcpServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(5678)) {
            while (true) {
                Socket client = server.accept();
                new Thread(new ServerHandler(client)).start();
            }
        }
    }
}

class ServerHandler implements Runnable {
    private final Socket socket;
    public ServerHandler(Socket socket) { this.socket = socket; }

    @Override
    public void run() {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
            String line;
            while ((line = in.readLine()) != null) {
                out.println("Response: " + line);
                if ("end".equals(line)) break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. TCP 連接池:複用昂貴資源

頻繁創建/銷毀 Socket 開銷大,參照數據庫連接池思想,預先建立連接池複用連接。

public class TcpConnectionPool {
    private final Socket[] sockets;
    private final boolean[] inUse;
    private final InetAddress address;
    private final int port;

    public TcpConnectionPool(InetAddress address, int port, int poolSize) throws IOException {
        this.address = address; this.port = port;
        this.sockets = new Socket[poolSize];
        this.inUse = new boolean[poolSize];
        for (int i = 0; i < poolSize; i++) {
            sockets[i] = new Socket(address, port);
        }
    }

    public synchronized Socket borrow() throws Exception {
        for (int i = 0; i < sockets.length; i++) {
            if (!inUse[i]) { inUse[i] = true; return sockets[i]; }
        }
        throw new IllegalStateException("連接池耗盡");
    }

    public synchronized void release(Socket socket) {
        for (int i = 0; i < sockets.length; i++) {
            if (sockets[i] == socket) { inUse[i] = false; break; }
        }
    }

    public void shutdown() {
        for (Socket s : sockets) closeQuietly(s);
    }
}

生產環境建議使用成熟框架(如 Apache Commons Pool、HikariCP 擴展)以獲得健壯的生命週期管理、空閒檢測、動態擴縮容等能力。

二、UDP 無連接數據報通信

UDP 適用於實時性要求高、容忍丟包的場景(視頻流、即時遊戲)。核心類為 DatagramSocket 與 DatagramPacket。

客戶端發送

public class UdpClient {
    public static void main(String[] args) throws IOException {
        InetAddress server = InetAddress.getLocalHost();
        int port = 5678;
        try (DatagramSocket socket = new DatagramSocket();
             BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {
            String line;
            while ((line = console.readLine()) != null) {
                byte[] data = line.getBytes();
                DatagramPacket packet = new DatagramPacket(data, data.length, server, port);
                socket.send(packet);
                if ("end".equals(line)) break;
            }
        }
    }
}

服務端接收

public class UdpServer {
    public static void main(String[] args) throws IOException {
        try (DatagramSocket socket = new DatagramSocket(5678)) {
            byte[] buffer = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            while (true) {
                socket.receive(packet);
                String msg = new String(packet.getData(), 0, packet.getLength());
                System.out.println(packet.getAddress().getHostAddress() + ": " + msg);
                if ("end".equals(msg)) break;
                packet.setLength(buffer.length); // 重置長度供下次接收
            }
        }
    }
}

注意:UDP 無連接特性意味著客戶端發送數據時不會因服務端未啟動而拋出異常,需自行設計心跳或應答機制保證可達性。

三、IP 多播:一對多高效分發

多播使用 D 類 IP 地址(224.0.0.0 ~ 239.255.255.255),基於 UDP 實現一對多通信。核心類 MulticastSocket 提供 joinGroup/leaveGroup 管理組成員。

發送端

public class MulticastSender {
    public static void main(String[] args) throws IOException {
        InetAddress group = InetAddress.getByName("230.0.0.1");
        int port = 5678;
        try (MulticastSocket socket = new MulticastSocket();
             BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {
            String line;
            while ((line = console.readLine()) != null) {
                byte[] data = line.getBytes();
                DatagramPacket packet = new DatagramPacket(data, data.length, group, port);
                socket.send(packet);
                if ("end".equals(line)) break;
            }
        }
    }
}

接收端

public class MulticastReceiver {
    public static void main(String[] args) throws IOException {
        int port = 5678;
        InetAddress group = InetAddress.getByName("230.0.0.1");
        try (MulticastSocket socket = new MulticastSocket(port)) {
            socket.joinGroup(group);
            byte[] buffer = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            while (true) {
                socket.receive(packet);
                String msg = new String(packet.getData(), 0, packet.getLength());
                System.out.println("收到: " + msg);
                if ("end".equals(msg)) break;
                packet.setLength(buffer.length);
            }
        }
    }
}

四、NIO:非阻塞 I/O 與選擇器模型

JDK 1.4 引入 NIO,核心三大組件:Channel(通道)、Buffer(緩衝區)、Selector(選擇器)。支持單線程管理成千上萬連接,是 Netty、MINA 等高性能網絡框架的基石。

基礎 SocketChannel 示例

public class NioClient {
    public static void main(String[] args) throws IOException {
        SocketChannel channel = SocketChannel.open();
        channel.connect(new InetSocketAddress("127.0.0.1", 5678));
        channel.configureBlocking(true); // 演示阻塞模式

        Charset charset = StandardCharsets.UTF_8;
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        // 發送 HTTP 請求
        String request = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";
        channel.write(charset.encode(request));

        // 讀取響應
        while (channel.read(buffer) != -1) {
            buffer.flip();
            System.out.print(charset.decode(buffer));
            buffer.clear();
        }
        channel.close();
    }
}

進階方向:生產級 NIO 應用應採用 Selector 實現單線程多路複用,結合 ByteBuffer 的零拷貝、直接內存等特性,並妥善處理半包/黏包、編解碼、空閒檢測等問題。推薦直接使用 Netty 等成熟框架。

總結與選型建議

模型適用場景優勢劣勢
TCP (BIO)低並發、強一致性交互(RPC、管理後台)編程簡單、可靠有序線程資源消耗大,難以支撐高並發
TCP (NIO/Netty)高並發、長連接(IM、推送、網關)單線程萬級連接、擴展性強編程複雜度高,需處理黏包/半包
UDP實時音視頻、遊戲同步、日誌收集延遲低、無連接開銷、支持廣播/多播不可靠、無序、需應用層保證可達性
多播股票行情推送、集群發現、IPTV網絡層面一對多,節省帶寬跨公網受限、不可靠、穿透 NAT 難

現代架構中,通常採用 Netty (NIO) 作為通用網絡框架底座,根據業務特性在應用層協議(HTTP/2、gRPC、WebSocket、自定義協議)上構建服務。

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