最新公告
  • 欢迎您光临极客文库,登录获取更多编程学习资源及文章!立即加入我们
  • BIO实现简单的多人在线聊天室功能

    简介

    本节我们利用BIO来实现一个简易版的多人在线的聊天室,该程序有以下几个特点:

    • 基于BIO模型
    • 支持多人同时在线
    • 每位用户的发言都会转发给其他在线的用户

    BIO编程模型

    关于BIO的知识可以自行百度,此处不细讲。

    时序图演示

    效果展示

    首先我们启动四个进程,一个服务端进程先启动,然后依次启动三个客户端进程,此时服务端进程会打印客户端的连接信息

    然后,我们依次用客户端1,2,3,发送消息,每个客户端发送的消息都将会被转发到其他客户端,服务端也打印所有消息。

    然后演示,当一个客户端输入”quit”后,将离线并失去客户端连接并关闭Socket

    服务端也打印出信息

     

    代码演示

    注意以下代码包含Tab标签

    服务端代码

    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    import java.io.Writer;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author geekerstar
     * @description 服务端
     */
    public class ChatServer {
        private int DEFAULT_PORT = 8888;
        private final String QUIT = "quit";
    
        private ServerSocket serverSocket;
    
        /**
         * 保存连接的客户端信息
         */
        private Map<Integer, Writer> connectedClients;
    
        public ChatServer() {
            connectedClients = new HashMap<>();
        }
    
        /**
         * 添加客户端
         *
         * @param socket
         */
        public synchronized void addClient(Socket socket) throws IOException {
            if (socket != null) {
                int port = socket.getPort();
                BufferedWriter writer = new BufferedWriter(
                        new OutputStreamWriter(socket.getOutputStream())
                );
                connectedClients.put(port, writer);
                System.out.println("客户端[" + port + "]已连接到服务器");
            }
        }
    
        /**
         * 移除客户端
         *
         * @param socket
         * @throws IOException
         */
        public synchronized void removeClient(Socket socket) throws IOException {
            if (socket != null) {
                int port = socket.getPort();
                if (connectedClients.containsKey(port)) {
                    connectedClients.get(port).close();
                }
                connectedClients.remove(port);
                System.out.println("客户端[" + port + "]已断开连接");
            }
        }
    
        /**
         * 转发消息
         *
         * @param socket
         * @param fwdMsg
         */
        public synchronized void forwardMessage(Socket socket, String fwdMsg) throws IOException {
            for (Integer id : connectedClients.keySet()) {
                // 排除发送者本人
                if (!id.equals(socket.getPort())) {
                    Writer writer = connectedClients.get(id);
                    writer.write(fwdMsg);
                    writer.flush();
                }
            }
        }
    
        /**
         * 监听是否准备退出标志
         *
         * @param msg
         * @return
         */
        public boolean readyToQuit(String msg) {
            return QUIT.equals(msg);
        }
    
        /**
         * 关闭serverSocket
         */
        public synchronized void close() {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                    System.out.println("关闭serverSocket");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public void start() {
            try {
                // 监听端口
                serverSocket = new ServerSocket(DEFAULT_PORT);
                System.out.println("启动服务器,监听端口:" + DEFAULT_PORT + "...");
    
                while (true) {
                    // 等待客户端连接
                    Socket socket = serverSocket.accept();
                    // 创建ChatHandler线程
                    new Thread(new ChatHandler(this, socket)).start();
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                close();
            }
        }
    
        public static void main(String[] args) {
            ChatServer server = new ChatServer();
            server.start();
        }
    }
    

     

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.Socket;
    
    /**
     * @author geekerstar
     * @description
     */
    public class ChatHandler implements Runnable {
    
        private ChatServer server;
        private Socket socket;
    
        public ChatHandler(ChatServer server, Socket socket) {
            this.server = server;
            this.socket = socket;
        }
    
        @Override
        public void run() {
            try {
                // 存储上线用户
                server.addClient(socket);
    
                // 读取用户发送的消息
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(socket.getInputStream())
                );
    
                String msg = null;
                while ((msg = reader.readLine()) != null) {
                    String fwdMsg = "客户端[" + socket.getPort() + "]:" + msg + "\n";
                    System.out.println(fwdMsg);
    
                    // 将消息转发给聊天室里在线的其他用户
                    server.forwardMessage(socket, fwdMsg);
    
                    // 检查用户是否准备退出
                    if (server.readyToQuit(msg)) {
                        break;
                    }
    
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    server.removeClient(socket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

     

    客户端代码

    import java.io.*;
    import java.net.Socket;
    
    /**
     * @author geekerstar
     * @description 客户端
     */
    public class ChatClient {
        private final String DEFAULT_SERVER_HOST = "127.0.0.1";
        private final int DEFAULT_SERVER_PORT = 8888;
        private final String QUIT = "quit";
    
        private Socket socket;
        private BufferedReader reader;
        private BufferedWriter writer;
    
        /**
         * 发送消息给服务器
         *
         * @param msg
         * @throws IOException
         */
        public void send(String msg) throws IOException {
            if (!socket.isOutputShutdown()) {
                writer.write(msg + "\n");
                writer.flush();
            }
        }
    
        /**
         * 从服务器接收消息
         *
         * @return
         * @throws IOException
         */
        public String receive() throws IOException {
            String msg = null;
            if (!socket.isInputShutdown()) {
                msg = reader.readLine();
            }
            return msg;
        }
    
        /**
         * 检查用户是否准备退出
         *
         * @param msg
         * @return
         */
        public boolean readyToQuit(String msg) {
            return QUIT.equals(msg);
        }
    
        /**
         * 关闭socket
         */
        public void close() {
            if (writer != null) {
                try {
                    System.out.println("关闭socket");
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
    
        public void start() {
            try {
                // 创建socket
                socket = new Socket(DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT);
    
                // 创建io流
                reader = new BufferedReader(
                        new InputStreamReader(socket.getInputStream())
                );
                writer = new BufferedWriter(
                        new OutputStreamWriter(socket.getOutputStream())
                );
    
                // 处理用户的输入
                new Thread(new UserInputHandler(this)).start();
    
                // 读取服务器转发的消息
                String msg = null;
                while ((msg = receive()) != null) {
                    System.out.println(msg);
    
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                close();
            }
        }
    
        public static void main(String[] args) {
            ChatClient chatClient = new ChatClient();
            chatClient.start();
        }
    }
    

     

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    /**
     * @author geekerstar
     * @description
     */
    public class UserInputHandler implements Runnable {
        private ChatClient chatClient;
    
        public UserInputHandler(ChatClient chatClient) {
            this.chatClient = chatClient;
        }
    
        @Override
        public void run() {
            BufferedReader consoleReader = new BufferedReader(
                    new InputStreamReader(System.in)
            );
    
            while (true) {
                try {
                    String input = consoleReader.readLine();
    
                    // 向服务器发送消息
                    chatClient.send(input);
    
                    // 检查用户是否准备退出
                    if (chatClient.readyToQuit(input)) {
                        break;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

     

    本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
    极客文库 » BIO实现简单的多人在线聊天室功能

    常见问题FAQ

    如果资源链接失效了怎么办?
    本站用户分享的所有资源都有自动备份机制,如果资源链接失效,请联系本站客服QQ:2580505920更新资源地址。
    如果用户分享的资源与描述不符怎么办?
    可以联系客服QQ:2580505920,如果要求合理可以安排退款或者退赞助积分。
    如何分享个人资源获取赞助积分或其他奖励?
    本站用户可以分享自己的资源,但是必须保证资源没有侵权行为。点击个人中心,根据操作填写并上传即可。资源所获收益完全归属上传者,每周可申请提现一次。
    如果您发现了本资源有侵权行为怎么办?
    及时联系客服QQ:2580505920,核实予以删除。

    参与讨论

    • 108会员总数(位)
    • 3700资源总数(个)
    • 5本周发布(个)
    • 2 今日发布(个)
    • 202稳定运行(天)

    欢迎加入「极客文库」,成为原创作者从这里开始!

    立即加入 了解更多
    成为赞助用户享有更多特权立即升级