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

Java Socket 通訊實戰:多線程聊天室服務端與客戶端完整實現

     編輯:Java 相關知識

架構設計

  • Server:ServerSocket 監聽端口 → accept 阻塞等待 → 每連接啟動獨立線程處理
  • Client:Socket 連接服務器 → 雙向流(輸入/輸出) → 主線程讀鍵盤發送、子線程接收顯示
  • 協議:文本行協議,以換行符分隔消息,"bye" 結束會話

服務端實現

public class ChatServer {
    private static final int PORT = 8857;
    private static final ExecutorService pool = Executors.newCachedThreadPool();

    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(PORT)) {
            System.out.println("服務器啟動,監聽端口: " + PORT);
            while (true) {
                Socket client = server.accept();
                System.out.println("新連接: " + client.getInetAddress());
                pool.submit(new ClientHandler(client));
            }
        }
    }

    static class ClientHandler implements Runnable {
        private final Socket socket;
        ClientHandler(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 msg;
                while ((msg = in.readLine()) != null) {
                    System.out.println("收到: " + msg);
                    if ("bye".equalsIgnoreCase(msg)) break;
                    // 廣播給所有客戶端 (簡化:僅回傳確認)
                    out.println("Server Echo: " + msg);
                }
            } catch (IOException e) {
                System.err.println("客戶端異常斷開: " + e.getMessage());
            } finally {
                try { socket.close(); } catch (IOException ignored) {}
                System.out.println("連接關閉: " + socket.getInetAddress());
            }
        }
    }
}

客戶端實現

public class ChatClient {
    private static final String HOST = "127.0.0.1";
    private static final int PORT = 8857;

    public static void main(String[] args) throws IOException {
        try (Socket socket = new Socket(HOST, PORT);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {

            System.out.println("已連接服務器,輸入 bye 退出");

            // 接收線程
            Thread receiver = new Thread(() -> {
                try {
                    String line;
                    while ((line = in.readLine()) != null) {
                        System.out.println("[Server] " + line);
                    }
                } catch (IOException ignored) {}
            });
            receiver.setDaemon(true);
            receiver.start();

            // 主線程發送
            String input;
            while ((input = console.readLine()) != null) {
                out.println(input);
                if ("bye".equalsIgnoreCase(input)) break;
            }
        }
    }
}

關鍵技術點

  1. 線程模型:服務端用線程池隔離客戶端,避免單線程阻塞;客戶端用守護線程接收,主線程發送
  2. 流緩衝:BufferedReader.readLine() + PrintWriter(autoFlush=true) 實現行協議
  3. 資源關閉:try-with-resources 保證 Socket/流異常時自動釋放
  4. 編碼統一:雙端指定 UTF-8,避免中文亂碼

生產級擴展方向

功能技術方案
用戶身份認證握手階段驗證 Token/JWT,關聯 Session 與 User
私聊/群聊維護 Map<String, PrintWriter> userChannels,消息路由
心跳保活定時發送 PING,超時未收到 PONG 則關閉連接
消息持久化接入 Redis Stream / Kafka / MySQL 異步落盤
高併發優化Netty NIO 事件循環替換 BIO 線程模型
SSL 加密SSLSocketFactory + 憑證雙向認證

常見問題排查

  • 連接被拒絕:防火牆攔截、端口衝突、Server 未啟動
  • 中文亂碼:雙端編碼不一致,強制指定 UTF-8
  • 消息粘包/半包:行協議天然分幀;若用二進制需自定義長度頭/分隔符
  • 客戶端異常斷開服務端未感知:啟用 socket.setKeepAlive(true) + 應用層心跳

總結

基於 ServerSocket/Socket + BIO 線程池 的聊天室,代碼量 < 100 行即可實現雙向通訊。核心模式:服務端接受分發、客戶端雙線程收發、行協議分幀、資源自動關閉。作為網絡編程入門經典,理解其阻塞模型局限(C10K 問題),為後續學習 Netty、gRPC、WebSocket 奠定堅實基礎。

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