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

基於 C/S 架構的 Java 聊天室實作

     編輯:Java 程式設計入門

專案概述

本文展示一個基於 Client/Server 架構的 Java 聊天室應用,採用 Socket 網路程式設計實現多用戶即時通訊。伺服器端負責連線管理、訊息廣播;客戶端提供圖形介面進行收發訊息。

系統架構設計

伺服器端核心職責

  • 監聽指定連接埠,接受客戶端連線請求
  • 為每個客戶端建立專屬執行緒處理通訊
  • 維護線上用戶列表(執行緒安全集合)
  • 廣播訊息給所有線上用戶
  • 處理用戶上線/下線通知

客戶端核心職責

  • 連接伺服器(IP + 連接埠)
  • 啟動接收執行緒持續監聽伺服器訊息
  • 提供 GUI 介面輸入/顯示訊息
  • 處理連線中斷與重連邏輯

關鍵技術實作

1. 伺服器主類別

public class ChatServer {
    private static final int PORT = 8888;
    private ServerSocket serverSocket;
    // 執行緒安全的用戶集合
    private static Map onlineUsers = new ConcurrentHashMap<>();
    
    public void start() {
        try {
            serverSocket = new ServerSocket(PORT);
            System.out.println("伺服器啟動,監聽連接埠 " + PORT);
            
            while (true) {
                Socket clientSocket = serverSocket.accept();
                new ClientHandler(clientSocket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    // 廣播訊息給所有用戶
    public static void broadcast(String message, String fromUser) {
        for (PrintWriter writer : onlineUsers.values()) {
            writer.println(message);
            writer.flush();
        }
    }
    
    public static void main(String[] args) {
        new ChatServer().start();
    }
}

2. 客戶端處理執行緒

class ClientHandler extends Thread {
    private Socket socket;
    private String userName;
    private BufferedReader in;
    private PrintWriter out;
    
    public ClientHandler(Socket socket) {
        this.socket = socket;
    }
    
    @Override
    public void run() {
        try {
            in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
            out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);
            
            // 登入流程:第一條訊息作為用戶名
            userName = in.readLine();
            if (userName == null) return;
            
            // 註冊上線
            ChatServer.onlineUsers.put(userName, out);
            ChatServer.broadcast("[系統] " + userName + " 上線了", "SYSTEM");
            
            // 持續讀取訊息並廣播
            String message;
            while ((message = in.readLine()) != null) {
                ChatServer.broadcast("[" + userName + "] " + message, userName);
            }
        } catch (IOException e) {
            // 連線中斷處理
        } finally {
            // 清理資源
            if (userName != null) {
                ChatServer.onlineUsers.remove(userName);
                ChatServer.broadcast("[系統] " + userName + " 下線了", "SYSTEM");
            }
            closeResources();
        }
    }
    
    private void closeResources() {
        try { if (in != null) in.close(); } catch (IOException ignored) {}
        try { if (out != null) out.close(); } catch (Exception ignored) {}
        try { if (socket != null) socket.close(); } catch (IOException ignored) {}
    }
}

3. 客戶端 GUI(Swing 實作)

public class ChatClient extends JFrame {
    private static final String SERVER_IP = "127.0.0.1";
    private static final int SERVER_PORT = 8888;
    
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    private JTextArea messageArea;
    private JTextField inputField;
    private JButton sendButton;
    
    public ChatClient() {
        initUI();
        connectToServer();
    }
    
    private void initUI() {
        setTitle("Java 聊天室");
        setSize(500, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        
        messageArea = new JTextArea();
        messageArea.setEditable(false);
        add(new JScrollPane(messageArea), BorderLayout.CENTER);
        
        JPanel bottomPanel = new JPanel(new BorderLayout());
        inputField = new JTextField();
        sendButton = new JButton("發送");
        bottomPanel.add(inputField, BorderLayout.CENTER);
        bottomPanel.add(sendButton, BorderLayout.EAST);
        add(bottomPanel, BorderLayout.SOUTH);
        
        // 發送事件
        Action sendAction = new AbstractAction() {
            @Override public void actionPerformed(ActionEvent e) { sendMessage(); }
        };
        inputField.addActionListener(sendAction);
        sendButton.addActionListener(sendAction);
    }
    
    private void connectToServer() {
        try {
            socket = new Socket(SERVER_IP, SERVER_PORT);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
            out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);
            
            // 彈窗輸入用戶名
            String name = JOptionPane.showInputDialog(this, "請輸入暱稱:", "登入", JOptionPane.PLAIN_MESSAGE);
            if (name == null || name.trim().isEmpty()) {
                System.exit(0);
            }
            out.println(name.trim());
            
            // 啟動接收執行緒
            new Thread(this::receiveMessages).start();
        } catch (IOException e) {
            JOptionPane.showMessageDialog(this, "無法連接伺服器:" + e.getMessage());
            System.exit(1);
        }
    }
    
    private void receiveMessages() {
        try {
            String message;
            while ((message = in.readLine()) != null) {
                final String msg = message;
                SwingUtilities.invokeLater(() -> messageArea.append(msg + "\n"));
            }
        } catch (IOException e) {
            SwingUtilities.invokeLater(() -> 
                JOptionPane.showMessageDialog(this, "連線中斷:" + e.getMessage()));
        }
    }
    
    private void sendMessage() {
        String text = inputField.getText().trim();
        if (!text.isEmpty()) {
            out.println(text);
            inputField.setText("");
        }
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(ChatClient::new);
    }
}

進階擴充方向

功能實作方向
私聊協議擴充:@username message,伺服器查找特定用戶 PrintWriter 發送
聊天室分群引入 Room 概念,用戶加入/離開房間,廣播限定房間成員
訊息持久化整合資料庫(MySQL/Redis),支援歷史訊息查詢
檔案傳輸協議支援二進位資料,採用分塊傳輸避免大檔案阻塞
SSL 加密使用 SSLSocketFactory 建立加密通道
心跳檢測定期發送 PING/PONG,偵測僵屍連線

常見問題與解決

  1. 中文亂碼:統一指定 UTF-8 編碼建立 Reader/Writer
  2. GUI 凍結:網路 I/O 必須在背景執行緒,Swing 更新用 SwingUtilities.invokeLater()
  3. 資源洩漏:finally 區塊確保關閉 Socket、Stream
  4. 併發安全:用 ConcurrentHashMap 或 Collections.synchronizedMap() 管理用戶集合

總結

C/S 架構聊天室是學習 Java 網路程式設計、多執行緒、Swing GUI、併發集合的經典實作專案。從基礎的訊息廣播延伸至私聊、分群、持久化、加密等進階功能,能全面鍛鍊後端架構設計能力。建議初學者先跑通基礎版本,再逐步加入擴充功能,體會架構演進過程。

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