本文目录导读:

我来为你提供一个完整的Java群聊案例,包含客户端和服务器端。
项目结构
chat-app/
├── src/
│ ├── Server.java # 服务器端
│ ├── Client.java # 客户端
│ ├── ClientHandler.java # 客户端处理线程
│ └── Message.java # 消息实体类
完整代码实现
Message 类(消息实体)
import java.io.Serializable;
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
private String type; // 消息类型: JOIN, LEAVE, CHAT, SYSTEM
private String sender; // 发送者
private String content; // 消息内容
private long timestamp; // 时间戳
public Message(String type, String sender, String content) {
this.type = type;
this.sender = sender;
this.content = content;
this.timestamp = System.currentTimeMillis();
}
// Getters and Setters
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getSender() { return sender; }
public void setSender(String sender) { this.sender = sender; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public long getTimestamp() { return timestamp; }
public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
@Override
public String toString() {
String time = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new java.util.Date(timestamp));
if ("SYSTEM".equals(type)) {
return String.format("[%s] [系统] %s", time, content);
}
return String.format("[%s] %s: %s", time, sender, content);
}
}
Server 类(服务器端)
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class Server {
private ServerSocket serverSocket;
private final int PORT = 8888;
// 存储所有在线客户端连接
private static ConcurrentHashMap<String, ClientHandler> clients = new ConcurrentHashMap<>();
public Server() {
System.out.println("===== 群聊服务器启动 =====");
}
public void start() {
try {
serverSocket = new ServerSocket(PORT);
System.out.println("服务器已启动,等待客户端连接...");
System.out.println("监听端口: " + PORT);
while (true) {
Socket socket = serverSocket.accept();
System.out.println("新客户端连接: " + socket.getRemoteSocketAddress());
// 为每个客户端创建一个处理线程
ClientHandler clientHandler = new ClientHandler(socket, this);
Thread thread = new Thread(clientHandler);
thread.start();
}
} catch (IOException e) {
System.err.println("服务器启动失败: " + e.getMessage());
}
}
// 添加客户端到在线列表
public synchronized void addClient(String username, ClientHandler handler) {
clients.put(username, handler);
broadcast(new Message("JOIN", "系统", username + " 加入了群聊"));
System.out.println("当前在线用户数: " + clients.size());
printOnlineUsers();
}
// 移除客户端
public synchronized void removeClient(String username) {
if (username != null) {
clients.remove(username);
broadcast(new Message("LEAVE", "系统", username + " 离开了群聊"));
System.out.println("当前在线用户数: " + clients.size());
printOnlineUsers();
}
}
// 广播消息给所有客户端
public void broadcast(Message message) {
for (ClientHandler handler : clients.values()) {
handler.sendMessage(message);
}
}
// 获取在线用户列表
public List<String> getOnlineUsers() {
return new ArrayList<>(clients.keySet());
}
// 打印在线用户
private void printOnlineUsers() {
System.out.println("在线用户: " + String.join(", ", clients.keySet()));
}
public static void main(String[] args) {
Server server = new Server();
server.start();
}
}
ClientHandler 类(客户端处理线程)
import java.io.*;
import java.net.Socket;
public class ClientHandler implements Runnable {
private Socket socket;
private Server server;
private ObjectInputStream input;
private ObjectOutputStream output;
private String username;
public ClientHandler(Socket socket, Server server) {
this.socket = socket;
this.server = server;
}
@Override
public void run() {
try {
// 初始化对象流
output = new ObjectOutputStream(socket.getOutputStream());
input = new ObjectInputStream(socket.getInputStream());
// 接收用户名
Message joinMessage = (Message) input.readObject();
this.username = joinMessage.getSender();
// 添加客户端到服务器列表
server.addClient(username, this);
// 发送欢迎消息
Message welcome = new Message("SYSTEM", "系统",
"欢迎加入群聊!当前在线人数: " + server.getOnlineUsers().size());
sendMessage(welcome);
// 发送当前在线用户列表
Message userList = new Message("SYSTEM", "系统",
"当前在线用户: " + String.join(", ", server.getOnlineUsers()));
sendMessage(userList);
// 循环接收客户端消息
while (true) {
Message message = (Message) input.readObject();
if ("CHAT".equals(message.getType())) {
// 广播聊天消息
server.broadcast(message);
} else if ("EXIT".equals(message.getType())) {
break;
}
}
} catch (IOException | ClassNotFoundException e) {
System.out.println(username + " 连接断开");
} finally {
// 移除客户端
server.removeClient(username);
closeConnection();
}
}
// 发送消息给客户端
public void sendMessage(Message message) {
try {
output.writeObject(message);
output.flush();
} catch (IOException e) {
System.err.println("发送消息失败: " + e.getMessage());
}
}
// 关闭连接
private void closeConnection() {
try {
if (input != null) input.close();
if (output != null) output.close();
if (socket != null) socket.close();
} catch (IOException e) {
System.err.println("关闭连接失败: " + e.getMessage());
}
}
}
Client 类(客户端)
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Client {
private Socket socket;
private ObjectOutputStream output;
private ObjectInputStream input;
private String username;
private static final String SERVER_HOST = "localhost";
private static final int SERVER_PORT = 8888;
public Client(String username) {
this.username = username;
}
public void start() {
try {
// 连接服务器
socket = new Socket(SERVER_HOST, SERVER_PORT);
output = new ObjectOutputStream(socket.getOutputStream());
input = new ObjectInputStream(socket.getInputStream());
System.out.println("已连接到服务器: " + SERVER_HOST + ":" + SERVER_PORT);
System.out.println("=" .repeat(50));
System.out.println("群聊系统已启动");
System.out.println("输入 /help 查看命令帮助");
System.out.println("输入 /quit 退出群聊");
System.out.println("=" .repeat(50));
// 发送用户名
Message joinMessage = new Message("JOIN", username, username + " 加入了群聊");
output.writeObject(joinMessage);
output.flush();
// 启动接收消息的线程
Thread receiveThread = new Thread(this::receiveMessages);
receiveThread.setDaemon(true);
receiveThread.start();
// 处理用户输入
handleUserInput();
} catch (IOException e) {
System.err.println("无法连接到服务器: " + e.getMessage());
}
}
// 接收服务器消息
private void receiveMessages() {
try {
while (true) {
Message message = (Message) input.readObject();
System.out.println(message);
}
} catch (IOException | ClassNotFoundException e) {
if (!"Connection reset".equals(e.getMessage())) {
System.err.println("与服务器连接断开");
}
}
}
// 处理用户输入
private void handleUserInput() {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("> ");
String inputText = scanner.nextLine();
// 检查命令
if (inputText.equalsIgnoreCase("/quit") || inputText.equalsIgnoreCase("/exit")) {
try {
Message exitMessage = new Message("EXIT", username, "退出群聊");
output.writeObject(exitMessage);
output.flush();
break;
} catch (IOException e) {
System.err.println("发送退出消息失败");
}
} else if (inputText.equalsIgnoreCase("/help")) {
printHelp();
} else if (inputText.startsWith("/")) {
System.out.println("未知命令,输入 /help 查看帮助");
} else {
// 发送聊天消息
try {
Message chatMessage = new Message("CHAT", username, inputText);
output.writeObject(chatMessage);
output.flush();
} catch (IOException e) {
System.err.println("发送消息失败: " + e.getMessage());
break;
}
}
}
// 清理资源
closeConnection();
}
// 打印帮助信息
private void printHelp() {
System.out.println("\n===== 群聊命令帮助 =====");
System.out.println("/help - 显示帮助信息");
System.out.println("/quit - 退出群聊");
System.out.println("其他任何输入都会作为消息发送");
System.out.println("=========================\n");
}
// 关闭连接
private void closeConnection() {
try {
if (output != null) output.close();
if (input != null) input.close();
if (socket != null) socket.close();
System.out.println("已退出群聊");
} catch (IOException e) {
System.err.println("关闭连接失败");
}
System.exit(0);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入您的用户名: ");
String username = scanner.nextLine().trim();
if (username.isEmpty()) {
username = "用户" + (int)(Math.random() * 1000);
System.out.println("使用默认用户名: " + username);
}
Client client = new Client(username);
client.start();
}
}
编译和运行
编译所有Java文件
javac *.java
启动服务器
java Server
启动多个客户端(不同终端)
# 终端1 java Client # 终端2 java Client # 终端3 java Client
运行效果示例
===== 群聊服务器启动 =====
服务器已启动,等待客户端连接...
监听端口: 8888
新客户端连接: /127.0.0.1:56789
用户1 加入了群聊
当前在线用户数: 1
在线用户: [用户1]
客户端效果:
> 大家好
[2024-01-15 10:30:25] 用户1: 大家好
[2024-01-15 10:30:26] 用户2: 大家好
> /help
===== 群聊命令帮助 =====
/help - 显示帮助信息
/quit - 退出群聊
功能特性
- 多用户支持:支持多个客户端同时连接
- 同步消息:所有用户实时同步聊天消息
- 在线状态:显示在线用户列表
- 系统消息:欢迎、离开等系统通知
- 命令支持:/help、/quit等命令
- 线程安全:使用ConcurrentHashMap保证并发安全
这个实现是基础版本,你可以根据需要扩展更多功能,如私聊、表情、文件传输等。