Java聊天室案例

wen java案例 2

本文目录导读:

Java聊天室案例

  1. 项目结构
  2. 服务器端代码
  3. 客户端代码
  4. 运行方法
  5. 功能说明
  6. 运行示例
  7. 扩展建议

我将为您创建一个基于Java Socket的简单聊天室案例,包含服务器端和客户端,这个案例使用控制台界面,支持多用户同时在线聊天。

项目结构

chatroom/
├── src/
│   ├── ChatServer.java    # 服务器端
│   ├── ChatClient.java    # 客户端
│   └── UserThread.java    # 客户端线程处理

服务器端代码

import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer {
    private static final int PORT = 12345;
    private static Set<PrintWriter> clients = new HashSet<>();
    private static Map<String, PrintWriter> clientNames = new HashMap<>();
    private static Map<String, String> userNames = new HashMap<>();
    public static void main(String[] args) {
        System.out.println("=== 聊天室服务器启动 ===");
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            System.out.println("服务器正在端口 " + PORT + " 监听...");
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("新客户端连接: " + socket.getInetAddress());
                UserThread userThread = new UserThread(socket);
                Thread thread = new Thread(userThread);
                thread.start();
            }
        } catch (IOException e) {
            System.err.println("服务器错误: " + e.getMessage());
        }
    }
    // 广播消息给所有客户端
    public static synchronized void broadcast(String message, String sender) {
        for (PrintWriter client : clients) {
            client.println("[广播] " + sender + ": " + message);
        }
    }
    // 发送私聊消息
    public static synchronized boolean sendPrivateMessage(String toUser, String message, String sender) {
        PrintWriter targetClient = clientNames.get(toUser);
        if (targetClient != null) {
            targetClient.println("[私聊] " + sender + ": " + message);
            return true;
        }
        return false;
    }
    // 获取在线用户列表
    public static synchronized String getOnlineUsers() {
        if (userNames.isEmpty()) {
            return "暂无在线用户";
        }
        StringBuilder users = new StringBuilder("在线用户: ");
        for (String name : userNames.keySet()) {
            users.append(name).append(" ");
        }
        return users.toString();
    }
    // 添加新客户端
    public static synchronized void addClient(String username, PrintWriter writer, Socket socket) {
        clients.add(writer);
        clientNames.put(username, writer);
        userNames.put(username, socket.getInetAddress().toString());
        // 通知所有用户
        broadcast(username + " 加入了聊天室", "系统");
        writer.println("欢迎 " + username + " 加入聊天室!");
        writer.println(getOnlineUsers());
    }
    // 移除客户端
    public static synchronized void removeClient(String username, PrintWriter writer) {
        clients.remove(writer);
        clientNames.remove(username);
        userNames.remove(username);
        broadcast(username + " 离开了聊天室", "系统");
    }
    // 内部类:处理每个客户端连接
    static class UserThread implements Runnable {
        private Socket socket;
        private PrintWriter writer;
        private BufferedReader reader;
        private String username;
        public UserThread(Socket socket) {
            this.socket = socket;
            try {
                writer = new PrintWriter(socket.getOutputStream(), true);
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            } catch (IOException e) {
                System.err.println("创建客户端线程失败: " + e.getMessage());
            }
        }
        @Override
        public void run() {
            try {
                // 获取用户名
                writer.println("请输入用户名: ");
                username = reader.readLine();
                if (username == null || username.trim().isEmpty()) {
                    writer.println("用户名不能为空,连接已关闭。");
                    socket.close();
                    return;
                }
                addClient(username, writer, socket);
                writer.println("输入 /quit 退出聊天室");
                writer.println("输入 /list 查看在线用户");
                writer.println("输入 /msg [用户名] [消息] 发送私聊");
                String input;
                while ((input = reader.readLine()) != null) {
                    if (input.equalsIgnoreCase("/quit")) {
                        break;
                    } else if (input.equalsIgnoreCase("/list")) {
                        writer.println(getOnlineUsers());
                    } else if (input.startsWith("/msg")) {
                        String[] parts = input.split(" ", 3);
                        if (parts.length == 3) {
                            boolean success = sendPrivateMessage(parts[1], parts[2], username);
                            if (!success) {
                                writer.println("用户 " + parts[1] + " 不在线或不存在");
                            }
                        } else {
                            writer.println("私聊格式: /msg [用户名] [消息]");
                        }
                    } else {
                        broadcast(input, username);
                    }
                }
                removeClient(username, writer);
                socket.close();
            } catch (IOException e) {
                System.err.println("客户端 " + username + " 连接断开");
                removeClient(username, writer);
                try {
                    socket.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
}

客户端代码

import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ChatClient {
    private static final String HOST = "localhost";
    private static final int PORT = 12345;
    private Socket socket;
    private PrintWriter out;
    private BufferedReader in;
    private Scanner scanner;
    public static void main(String[] args) {
        ChatClient client = new ChatClient();
        client.start();
    }
    public void start() {
        scanner = new Scanner(System.in);
        try {
            socket = new Socket(HOST, PORT);
            out = new PrintWriter(socket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("已连接到聊天室服务器...");
            // 创建线程监听服务器消息
            new Thread(new MessageListener()).start();
            // 用户输入循环
            handleUserInput();
        } catch (IOException e) {
            System.err.println("连接服务器失败: " + e.getMessage());
            System.exit(1);
        } finally {
            try {
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    private void handleUserInput() throws IOException {
        String input;
        while (true) {
            input = scanner.nextLine();
            out.println(input);
            if (input.equalsIgnoreCase("/quit")) {
                System.out.println("正在退出聊天室...");
                break;
            }
        }
    }
    // 内部类:监听服务器消息
    class MessageListener implements Runnable {
        @Override
        public void run() {
            String message;
            try {
                while ((message = in.readLine()) != null) {
                    System.out.println(message);
                }
            } catch (IOException e) {
                System.err.println("连接已断开");
            }
        }
    }
}

运行方法

编译代码

cd chatroom/src
javac ChatServer.java
javac ChatClient.java

启动服务器

java ChatServer

启动多个客户端

每个客户端都需要新开一个终端:

java ChatClient

功能说明

命令 功能
/quit 退出聊天室
/list 查看在线用户
/msg [用户名] [消息] 发送私聊消息
普通文字 广播给所有人

运行示例

服务器端:

=== 聊天室服务器启动 ===
服务器正在端口 12345 监听...
新客户端连接: /127.0.0.1
新客户端连接: /127.0.0.1

客户端1(用户:Alice):

请输入用户名: Alice
欢迎 Alice 加入聊天室!
在线用户: Alice 
输入 /quit 退出聊天室
输入 /list 查看在线用户
输入 /msg [用户名] [消息] 发送私聊
[广播] 系统: Bob 加入了聊天室
[广播] Bob: 大家好!
[私聊] Bob: Alice,你好!

客户端2(用户:Bob):

请输入用户名: Bob
欢迎 Bob 加入聊天室!
在线用户: Alice Bob 
输入 /quit 退出聊天室
输入 /list 查看在线用户
输入 /msg [用户名] [消息] 发送私聊
[广播] 系统: Bob 加入了聊天室
[广播] Bob: 大家好!
[私聊] Bob: Alice,你好!

扩展建议

  1. 图形界面:使用 Swing 或 JavaFX 实现 GUI 界面
  2. 表情/文件传输:添加表情符号、图片或文件传输功能
  3. 消息日志:将聊天记录保存到文件
  4. 用户认证:添加登录和密码验证
  5. 房间管理:支持创建多个聊天房间
  6. 消息加密:添加 SSL/TLS 加密

这个案例展示了 Java Socket 编程的核心概念,包括多线程、网络通信、同步等,可以作为学习网络编程的基础。

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