近期閒暇之餘,決定重溫 Java 網路程式設計的基礎,便動手實作了一個基於 UDP 協定的簡易聊天室。雖然現代開發較少直接操作 Socket,但這類練習有助於鞏固網路通訊的核心概念。本文將完整呈現從伺服端、客戶端到訊息實體類的程式碼結構,並附上測試範例。
這個聊天室支援多房間機制:使用者輸入房間 ID 與暱稱即可加入。同一房間內的訊息會即時廣播給所有成員,不同房間則互不干擾。執行畫面中,「聊天室001」的小紅與小綠正常對話,而「聊天室002」的小黑則獨自一人,完美展示房間隔離效果。
伺服器職責單純明確:
package com.tsr.simplechat.receive_server;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.HashMap;
import com.google.gson.Gson;
import com.tsr.simplechat.bean.MessageEntity;
import com.tsr.simplechat.client.ChatClient;
public class ChatServer extends Thread {
private static final int PORT = 10000;
private static DatagramSocket server = null;
private static HashMap<String, ArrayList<ChatClient>> groups = new HashMap<>();
public ChatServer() {
try {
server = new DatagramSocket(PORT);
} catch (SocketException e) {
e.printStackTrace();
}
}
public static void logInGroup(String groupID, ChatClient client) {
ArrayList<ChatClient> clients = groups.get(groupID);
if (clients == null) {
clients = new ArrayList<>();
}
clients.add(client);
groups.put(groupID, clients);
}
@Override
public void run() {
while (true) {
receiveMessage();
}
}
private void receiveMessage() {
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while (true) {
try {
server.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
String content = new String(packet.getData(), 0, packet.getLength());
Gson gson = new Gson();
MessageEntity me = gson.fromJson(content, MessageEntity.class);
ArrayList<ChatClient> clients = groups.get(me.getGroupId());
if (clients != null) {
for (ChatClient client : clients) {
client.pushBackMessage(me);
}
}
}
}
}
採用 AWT 建構簡易 GUI,包含訊息顯示區、輸入框與發送按鈕。核心邏輯:
pushBackMessage 供伺服器推送訊息更新 UIpackage com.tsr.simplechat.client;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.net.*;
import com.tsr.simplechat.bean.MessageEntity;
import com.tsr.simplechat.receive_server.ChatServer;
public class ChatClient extends Frame {
private static final long serialVersionUID = 1L;
private String groupID, clientName;
private DatagramSocket msg_send;
private final int PORT = 10000;
private InetAddress ip;
private TextField tf = new TextField(20);
private TextArea ta = new TextArea();
private Button send = new Button("send");
public ChatClient(String groupID, String clientName) {
super("聊天室:" + groupID + "/" + clientName);
this.clientName = clientName;
this.groupID = groupID;
add("North", tf);
add("Center", ta);
add("South", send);
setSize(250, 250);
show();
init();
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
msg_send.close();
dispose();
System.exit(0);
}
});
}
private void init() {
ChatServer.logInGroup(groupID, this);
try {
msg_send = new DatagramSocket();
ip = InetAddress.getByName("127.0.0.1");
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean action(Event evt, Object arg) {
if (evt.target.equals(send)) {
try {
String content = tf.getText();
send_message(content);
tf.setText("");
} catch (Exception ioe) {
System.out.print(ioe.getMessage());
}
}
return true;
}
private void send_message(String content) {
String message = messageFormat(content);
byte[] buf = message.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, ip, PORT);
try {
msg_send.send(packet);
} catch (IOException e) {
System.out.println("IO 異常");
}
}
private String messageFormat(String content) {
StringBuffer buffer = new StringBuffer();
buffer.append("{\"groupId\":\"").append(groupID).append("\",");
buffer.append("\"userName\":\"").append(clientName).append("\",");
buffer.append("\"text\":\"").append(content).append("\"}");
return buffer.toString();
}
public void pushBackMessage(MessageEntity me) {
ta.append(me.getUserName() + ":" + me.getText() + "\n");
}
}
單純的 POJO,配合 Gson 進行 JSON 序列化/反序列化。
package com.tsr.simplechat.bean;
public class MessageEntity {
private String groupId;
private String userName;
private String text;
// Getter/Setter 略
}
一鍵啟動伺服器與三個客戶端,驗證多房間隔離功能。
import com.tsr.simplechat.client.ChatClient;
import com.tsr.simplechat.receive_server.ChatServer;
public class Test {
public static void main(String[] args) {
ChatServer server = new ChatServer();
server.start();
new ChatClient("001", "小紅");
new ChatClient("001", "小綠");
new ChatClient("002", "小黑");
}
}
此範例雖簡單,卻涵蓋 UDP 通訊、多執行緒、JSON 序列化、GUI 事件處理等核心技術。適合初學者理解 Java 網路程式基礎,也可作為擴充功能(如私聊、檔案傳輸)的起點。