本文展示一個基於 Client/Server 架構的 Java 聊天室應用,採用 Socket 網路程式設計實現多用戶即時通訊。伺服器端負責連線管理、訊息廣播;客戶端提供圖形介面進行收發訊息。
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();
}
}
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) {}
}
}
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,偵測僵屍連線 |
SwingUtilities.invokeLater()ConcurrentHashMap 或 Collections.synchronizedMap() 管理用戶集合C/S 架構聊天室是學習 Java 網路程式設計、多執行緒、Swing GUI、併發集合的經典實作專案。從基礎的訊息廣播延伸至私聊、分群、持久化、加密等進階功能,能全面鍛鍊後端架構設計能力。建議初學者先跑通基礎版本,再逐步加入擴充功能,體會架構演進過程。