最新公告
  • 新注册用户请前往个人中心绑定邮箱以便接收相关凭证邮件!!!点击前往个人中心
  • 使用 NIO 实现简单群聊系统

    代码演示

    可以和【使用 Netty 实现简单群聊系统(https://www.geekerstar.com/30862.html)】二者结合对比NIONetty使用的区别

    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ThreadLocalRandom;
    
    public class ChatServer {
        public static void main(String[] args) throws IOException {
            Selector selector = Selector.open();
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(8080));
            serverSocketChannel.configureBlocking(false);
            // 将accept事件绑定到selector上
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    
            while (true) {
                // 阻塞在select上
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                // 遍历selectKeys
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    // 如果是accept事件
                    if (selectionKey.isAcceptable()) {
                        ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
                        SocketChannel socketChannel = ssc.accept();
                        System.out.println("accept new conn: " + socketChannel.getRemoteAddress());
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        // 加入群聊
                        ChatHolder.join(socketChannel);
                    } else if (selectionKey.isReadable()) {
                        // 如果是读取事件
                        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        // 将数据读入到buffer中
                        int length = socketChannel.read(buffer);
                        if (length > 0) {
                            buffer.flip();
                            byte[] bytes = new byte[buffer.remaining()];
                            // 将数据读入到byte数组中
                            buffer.get(bytes);
    
                            // 换行符会跟着消息一起传过来
                            String content = new String(bytes, "UTF-8").replace("\r\n", "");
                            if (content.equalsIgnoreCase("quit")) {
                                // 退出群聊
                                ChatHolder.quit(socketChannel);
                                selectionKey.cancel();
                                socketChannel.close();
                            } else {
                                // 扩散
                                ChatHolder.propagate(socketChannel, content);
                            }
                        }
                    }
                    iterator.remove();
                }
            }
        }
    
        private static class ChatHolder {
            private static final Map<SocketChannel, String> USER_MAP = new ConcurrentHashMap<>();
    
            /**
             * 加入群聊
             * @param socketChannel
             */
            public static void join(SocketChannel socketChannel) {
                // 有人加入就给他分配一个id
                String userId = "用户"+ ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE);
                send(socketChannel, "您的id为:" + userId + "\n\r");
    
                for (SocketChannel channel : USER_MAP.keySet()) {
                    send(channel, userId + " 加入了群聊" + "\n\r");
                }
    
                // 将当前用户加入到map中
                USER_MAP.put(socketChannel, userId);
            }
    
            /**
             * 退出群聊
             * @param socketChannel
             */
            public static void quit(SocketChannel socketChannel) {
                String userId = USER_MAP.get(socketChannel);
                send(socketChannel, "您退出了群聊" + "\n\r");
                USER_MAP.remove(socketChannel);
    
                for (SocketChannel channel : USER_MAP.keySet()) {
                    if (channel != socketChannel) {
                        send(channel, userId + " 退出了群聊" + "\n\r");
                    }
                }
            }
    
            /**
             * 扩散说话的内容
             * @param socketChannel
             * @param content
             */
            public static void propagate(SocketChannel socketChannel, String content) {
                String userId = USER_MAP.get(socketChannel);
                for (SocketChannel channel : USER_MAP.keySet()) {
                    if (channel != socketChannel) {
                        send(channel, userId + ": " + content + "\n\r");
                    }
                }
            }
    
            /**
             * 发送消息
             * @param socketChannel
             * @param msg
             */
            private static void send(SocketChannel socketChannel, String msg) {
                try {
                    ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
                    writeBuffer.put(msg.getBytes());
                    writeBuffer.flip();
                    socketChannel.write(writeBuffer);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

     

    效果展示

    模拟群聊,启动四个 xshell窗口,模拟聊天

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

    常见问题FAQ

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

    参与讨论

    • 211会员总数(位)
    • 3737资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 869稳定运行(天)

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

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