Java写的一个简易版聊天系统

Java 聊天系统实现


下面是一个基于Java Socket编程的简单聊天系统实现,包含服务器端和客户端代码。


1. 服务器端代码 (ChatServer.java)

import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer {
    private static final int PORT = 12345;
    private static Set<ClientHandler> clientHandlers = new HashSet<>();
    
    public static void main(String[] args) {
        System.out.println("聊天服务器启动中...");
        
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            System.out.println("服务器已启动,等待客户端连接...");
            
            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("新客户端连接: " + clientSocket);
                
                ClientHandler clientHandler = new ClientHandler(clientSocket);
                clientHandlers.add(clientHandler);
                clientHandler.start();
            }
        } catch (IOException e) {
            System.err.println("服务器异常: " + e.getMessage());
        }
    }
    
    // 广播消息给所有客户端
    public static void broadcast(String message, ClientHandler excludeClient) {
        for (ClientHandler client : clientHandlers) {
            if (client != excludeClient) {
                client.sendMessage(message);
            }
        }
    }
    
    // 移除客户端
    public static void removeClient(ClientHandler client) {
        clientHandlers.remove(client);
        System.out.println("客户端断开连接: " + client.getClientSocket());
    }
    
    // 客户端处理线程
    private static class ClientHandler extends Thread {
        private Socket clientSocket;
        private PrintWriter out;
        private BufferedReader in;
        private String username;
        
        public ClientHandler(Socket socket) {
            this.clientSocket = socket;
        }
        
        public Socket getClientSocket() {
            return clientSocket;
        }
        
        @Override
        public void run() {
            try {
                out = new PrintWriter(clientSocket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                
                // 获取用户名
                out.println("请输入你的用户名:");
                username = in.readLine();
                System.out.println(username + " 加入了聊天室");
                broadcast(username + " 加入了聊天室", this);
                
                String clientMessage;
                while ((clientMessage = in.readLine()) != null) {
                    if (clientMessage.equalsIgnoreCase("exit")) {
                        break;
                    }
                    System.out.println(username + ": " + clientMessage);
                    broadcast(username + ": " + clientMessage, this);
                }
                
            } catch (IOException e) {
                System.err.println("客户端处理异常: " + e.getMessage());
            } finally {
                try {
                    if (clientSocket != null) {
                        clientSocket.close();
                    }
                } catch (IOException e) {
                    System.err.println("关闭客户端连接异常: " + e.getMessage());
                }
                removeClient(this);
                broadcast(username + " 离开了聊天室", null);
                System.out.println(username + " 离开了聊天室");
            }
        }
        
        public void sendMessage(String message) {
            out.println(message);
        }
    }
}


2. 客户端代码 (ChatClient.java)

import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ChatClient {
    private static final String SERVER_ADDRESS = "localhost";
    private static final int SERVER_PORT = 12345;
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        try (Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT)) {
            System.out.println("已连接到聊天服务器");
            
            // 启动消息接收线程
            new Thread(new MessageReceiver(socket)).start();
            
            // 处理用户输入
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            
            // 读取服务器欢迎消息
            String serverMessage;
            while ((serverMessage = in.readLine()) != null) {
                System.out.println(serverMessage);
                if (serverMessage.startsWith("请输入你的用户名:")) {
                    String username = scanner.nextLine();
                    out.println(username);
                } else {
                    String userInput = scanner.nextLine();
                    if (userInput.equalsIgnoreCase("exit")) {
                        out.println("exit");
                        break;
                    }
                    out.println(userInput);
                }
            }
            
        } catch (UnknownHostException e) {
            System.err.println("无法找到服务器: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("I/O异常: " + e.getMessage());
        } finally {
            scanner.close();
            System.out.println("已断开与服务器的连接");
        }
    }
    
    // 消息接收线程
    private static class MessageReceiver implements Runnable {
        private Socket socket;
        
        public MessageReceiver(Socket socket) {
            this.socket = socket;
        }
        
        @Override
        public void run() {
            try (BufferedReader in = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()))) {
                
                String serverMessage;
                while ((serverMessage = in.readLine()) != null) {
                    System.out.println(serverMessage);
                }
                
            } catch (IOException e) {
                System.err.println("接收消息异常: " + e.getMessage());
            }
        }
    }
}


3. 系统功能说明

服务器端功能

监听指定端口(12345)等待客户端连接

为每个客户端创建独立的处理线程

接收客户端消息并广播给所有其他客户端

处理客户端连接和断开事件

支持用户名设置

客户端功能

连接到指定服务器

设置用户名

发送消息到服务器

接收并显示其他用户的消息

支持退出命令("exit")


4. 如何运行

首先编译并运行服务器端:

javac ChatServer.java
java ChatServer


然后可以运行多个客户端(需要打开多个终端):

javac ChatClient.java
java ChatClient


在客户端中输入用户名后即可开始聊天


5. 扩展建议

图形界面‌:使用Java Swing或JavaFX为客户端添加图形界面

私聊功能‌:实现用户之间的私密聊天

用户列表‌:服务器维护在线用户列表并通知所有客户端

消息历史‌:保存聊天记录

加密通信‌:使用SSL/TLS加密通信内容

数据库支持‌:使用数据库存储用户信息和聊天记录

多房间支持‌:实现多个聊天室功能


6. 简单图形界面客户端示例 (可选)

如果你想为客户端添加简单的图形界面,可以使用以下代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class GUIChatClient {
    private JFrame frame;
    private JTextArea chatArea;
    private JTextField inputField;
    private PrintWriter out;
    private String username;
    
    public GUIChatClient() {
        initializeGUI();
        connectToServer();
    }
    
    private void initializeGUI() {
        frame = new JFrame("聊天客户端");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 400);
        
        chatArea = new JTextArea();
        chatArea.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(chatArea);
        
        inputField = new JTextField();
        inputField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                sendMessage();
            }
        });
        
        JButton sendButton = new JButton("发送");
        sendButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                sendMessage();
            }
        });
        
        JPanel bottomPanel = new JPanel(new BorderLayout());
        bottomPanel.add(inputField, BorderLayout.CENTER);
        bottomPanel.add(sendButton, BorderLayout.EAST);
        
        frame.add(scrollPane, BorderLayout.CENTER);
        frame.add(bottomPanel, BorderLayout.SOUTH);
        
        frame.setVisible(true);
    }
    
    private void connectToServer() {
        try {
            Socket socket = new Socket("localhost", 12345);
            out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            
            // 获取用户名
            username = JOptionPane.showInputDialog(frame, "请输入你的用户名:");
            out.println(username);
            
            // 启动消息接收线程
            new Thread(new MessageReceiver(in)).start();
            
        } catch (IOException e) {
            JOptionPane.showMessageDialog(frame, "连接服务器失败: " + e.getMessage(), 
                "错误", JOptionPane.ERROR_MESSAGE);
            System.exit(1);
        }
    }
    
    private void sendMessage() {
        String message = inputField.getText();
        if (!message.isEmpty()) {
            out.println(message);
            inputField.setText("");
        }
    }
    
    private class MessageReceiver implements Runnable {
        private BufferedReader in;
        
        public MessageReceiver(BufferedReader in) {
            this.in = in;
        }
        
        @Override
        public void run() {
            try {
                String message;
                while ((message = in.readLine()) != null) {
                    final String msg = message;
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            chatArea.append(msg + "
");
                        }
                    });
                }
            } catch (IOException e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        chatArea.append("与服务器的连接已断开
");
                    }
                });
            }
        }
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new GUIChatClient();
            }
        });
    }
}

这个简单的聊天系统展示了Java网络编程的基本概念,你可以根据需要进一步扩展和完善功能。


文章导航