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

Java Socket 實現 TCP/UDP 多線程通信完整實戰:服務端客戶端代碼、線程模型、常見坑點與優化

     編輯:Java 綜合教學

一、TCP 多線程通信

1.1 核心類

  • 服務端:ServerSocket(監聽)、Socket(連接)
  • 客戶端:Socket

1.2 服務端線程模型:One Thread Per Connection

while (true) {
    Socket client = serverSocket.accept(); // 阻塞等待
    new Thread(new ClientHandler(client)).start(); // 每連接一線程
}

1.3 完整代碼

ClientHandler.java(線程處理類)

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

    @Override
    public void run() {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
             PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true)) {

            String msg;
            while ((msg = in.readLine()) != null) {
                System.out.println("收到: " + msg);
                // 業務處理...
                out.println("Server Echo: " + msg);
            }
        } catch (IOException e) {
            log.error("Client error", e);
        } finally {
            closeQuietly(socket);
        }
    }
}

TCPServer.java

public class TCPServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(8888)) {
            System.out.println("TCP Server started on 8888");
            while (true) {
                Socket client = server.accept();
                System.out.println("新連接: " + client.getInetAddress());
                new Thread(new ClientHandler(client)).start();
            }
        }
    }
}

TCPClient.java

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

            out.println("Hello Server");
            System.out.println("服務端回應: " + in.readLine());
        }
    }
}

二、UDP 多線程通信

2.1 核心類

  • DatagramSocket:發送/接收數據報
  • DatagramPacket:數據報封裝(數據、長度、目標 IP/端口)

2.2 服務端:單 Socket + 多線程處理

public class UDPServer {
    public static void main(String[] args) throws IOException {
        try (DatagramSocket socket = new DatagramSocket(8800)) {
            byte[] buf = new byte[1024];
            System.out.println("UDP Server started on 8800");
            while (true) {
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                socket.receive(packet); // 阻塞接收
                new Thread(new UDPHandler(socket, packet)).start();
            }
        }
    }
}

class UDPHandler implements Runnable {
    private final DatagramSocket socket;
    private final DatagramPacket packet;
    public UDPHandler(DatagramSocket socket, DatagramPacket packet) {
        this.socket = socket; this.packet = packet;
    }
    @Override
    public void run() {
        String msg = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
        System.out.println("收到: " + msg);
        byte[] resp = "Server Received".getBytes(StandardCharsets.UTF_8);
        DatagramPacket respPacket = new DatagramPacket(resp, resp.length, packet.getAddress(), packet.getPort());
        try { socket.send(respPacket); } catch (IOException e) { log.error("Send failed", e); }
    }
}

2.3 UDPClient.java

public class UDPClient {
    public static void main(String[] args) throws IOException {
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress addr = InetAddress.getByName("localhost");
            byte[] data = "Hello UDP".getBytes(StandardCharsets.UTF_8);
            DatagramPacket packet = new DatagramPacket(data, data.length, addr, 8800);
            socket.send(packet);

            byte[] buf = new byte[1024];
            DatagramPacket resp = new DatagramPacket(buf, buf.length);
            socket.receive(resp);
            System.out.println("服務端回應: " + new String(resp.getData(), 0, resp.getLength(), StandardCharsets.UTF_8));
        }
    }
}

三、關鍵差異對比

特性TCPUDP
連接面向連接(三次握手)無連接
可靠性可靠、有序、無重複不可靠、無序、可能重複/丟失
流控/擁塞控制有無
數據單元字節流數據報
適用場景文件傳輸、HTTP、郵件、即時通訊核心視頻流、直播、DNS、SNMP、廣播
服務端 SocketServerSocket + 多 Socket單 DatagramSocket 共用

四、常見坑點與優化

問題原因解決
TCP 粘包/拆包流式傳輸無邊界定長、分隔符、長度前綴(Netty LengthFieldBasedFrameDecoder)
線程資源耗盡大量連接創建線程線程池、NIO 選擇器、Netty EventLoop
UDP 丟包無感知協議特性應用層 ACK/重傳/序列號(如 KCP、QUIC)
編碼亂碼未指定 Charset統一 StandardCharsets.UTF_8
端口佔用TIME_WAIT / 未釋放SO_REUSEADDR、優雅關閉
BufferedReader.readLine() 死循環對端未發送換行符自定義協議解碼器、read(char[])

五、進階優化方向

  1. 線程池化:ExecutorService pool = Executors.newFixedThreadPool(50); pool.execute(new ClientHandler(socket));
  2. NIO 非阻塞:Selector + ServerSocketChannel/SocketChannel,單線程處理萬級連接。
  3. Netty 框架:生產級首選,封裝 NIO、內存管理、編解碼、心跳、SSL、HTTP/2。
  4. 對象傳輸:ObjectOutputStream 序列化對象,或 Protobuf/JSON 高性能編解碼。
  5. 優雅關閉:註冊 ShutdownHook,關閉 ServerSocket、拒絕新連接、等待處理中任務完成。

六、總結

本文提供了可直接運行的 TCP/UDP 多線程通信完整代碼,涵蓋服務端線程模型、客戶端調用、核心 API 用法、協議差異、高頻坑點與生產級優化路線圖。建議先跑通 Demo,再逐步引入線程池、NIO、Netty 進階演進。

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