Java实现群聊案例

wen java案例 3

本文目录导读:

Java实现群聊案例

  1. 项目结构
  2. 完整代码实现
  3. 编译和运行
  4. 运行效果示例
  5. 功能特性

我来为你提供一个完整的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    - 退出群聊

功能特性

  1. 多用户支持:支持多个客户端同时连接
  2. 同步消息:所有用户实时同步聊天消息
  3. 在线状态:显示在线用户列表
  4. 系统消息:欢迎、离开等系统通知
  5. 命令支持:/help、/quit等命令
  6. 线程安全:使用ConcurrentHashMap保证并发安全

这个实现是基础版本,你可以根据需要扩展更多功能,如私聊、表情、文件传输等。

抱歉,评论功能暂时关闭!