美文网首页
NIO - 多人聊天室Demo代码

NIO - 多人聊天室Demo代码

作者: 夹胡碰 | 来源:发表于2021-03-08 11:45 被阅读0次

    1. 目录结构

    1. NioServer
    package com.xu.nio;
    
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.*;
    import java.nio.charset.Charset;
    import java.util.Iterator;
    import java.util.Set;
    
    /**
     * @author jiafupeng
     * @desc
     * @create 2021/3/7 19:11
     * @update 2021/3/7 19:11
     **/
    public class NioServer {
    
        /**
         * 启动
         */
        public void start() throws IOException {
            // 1. 创建Selector
            Selector selector = Selector.open();
            // 2. 通过ServerSocketChannel创建channel通道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 3. 为channel通道绑定监听端口
            serverSocketChannel.bind(new InetSocketAddress(8000));
            // 4. 设置channel为非阻塞模式
            serverSocketChannel.configureBlocking(false);
            // 5. 将channel注册到selector上,监听连接事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("服务器启动成功");
            // 6. 循环等待新接入的连接
            for(;;){
                // 阻塞 - 获取可用channel数量
                int readyChannels = selector.select();
                if(readyChannels == 0){continue;}
                // 获取可用channel的集合
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()){
                    // selectionKey实例
                    SelectionKey selectionKey = iterator.next();
                    // 移除
                    iterator.remove();
                    // 7. 根据就绪状态,调用对应方法处理业务逻辑
                    // 如果是 接入事件
                    if(selectionKey.isAcceptable()){
                        acceptHandler(selectionKey, selector);
                    }
                    // 如果是 可读事件
                    if(selectionKey.isReadable()){
                        readHandler(selectionKey, selector);
                    }
                }
            }
        }
    
        /**
         * 接入事件处理器
         */
        private void acceptHandler(SelectionKey selectionKey,
                                   Selector selector)
                throws IOException {
            ServerSocketChannel serverSocketChannel = (ServerSocketChannel)selectionKey.channel();
            // 要是接入事件,创建socketChannel
            SocketChannel socketChannel = serverSocketChannel.accept();
            // 将socketChannel设置为非阻塞工作模式
            socketChannel.configureBlocking(false);
            // 将channel注册到selector上,监听可读事件
            socketChannel.register(selector, SelectionKey.OP_READ);
            // 回复客户端提示信息
             socketChannel.write(Charset.forName("UTF-8").encode("<==== 欢迎进入聊天室 ====>"));
        }
    
        /**
         * 可读事件处理器
         */
        private void readHandler(SelectionKey selectionKey,
                                 Selector selector)
                throws IOException {
            // 要从 selectionKey 中获取已经就绪的channel
            SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
            // 创建buffer
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            // 循环读取客户端请求信息
            String request = "";
            while (socketChannel.read(byteBuffer) > 0){
                // 切换buffer为读模式
                byteBuffer.flip();
                // 读取buffer中的内容
                request += Charset.forName("UTF-8").decode(byteBuffer);
            }
            // 将channel再次注册到selector上,监听其他的可读事件
            socketChannel.register(selector, SelectionKey.OP_READ);
            // 将客户端发送的请求信息 广播给其他客户端
            if(request.length() > 0){
                broadCast(selector, socketChannel, request);
            }
        }
    
        private void broadCast(Selector selector,
                               SocketChannel sourceChannel, String request){
            Set<SelectionKey> selectionKeySet = selector.keys();
            selectionKeySet.stream().forEach(selectionKey -> {
                Channel targetChannel = selectionKey.channel();
    
                // 剔除发消息的客户端
                if (targetChannel instanceof SocketChannel
                        && targetChannel != sourceChannel) {
                    try {
                        // 将信息发送到targetChannel客户端
                        ((SocketChannel) targetChannel).write(
                                Charset.forName("UTF-8").encode(request));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    
        public static void main(String[] args) throws IOException {
            NioServer nioServer = new NioServer();
            nioServer.start();
        }
    }
    
    2. NioClient
    package com.xu.nio;
    
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.SocketChannel;
    import java.nio.charset.Charset;
    import java.util.Scanner;
    
    /**
     * @author jiafupeng
     * @desc
     * @create 2021/3/7 19:42
     * @update 2021/3/7 19:42
     **/
    public class NioClient {
    
        private String nickname;
    
        public NioClient(String nickname) {
            this.nickname = nickname;
        }
    
        public void start() throws IOException {
            // 连接服务器端
            SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8000));
    
            // 接受服务端响应
            Selector selector = Selector.open();
            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_READ);
            new Thread(new NioClientHandler(selector)).start();
    
            // 向服务器端发送数据
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNextLine()){
                String request = scanner.nextLine();
                if(request != null && request.length() > 0){
                    socketChannel.write(Charset.forName("UTF-8").encode(nickname + " : " + request));
                }
            }
        }
    }
    
    3. NioClientHandler
    package com.xu.nio;
    
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.SocketChannel;
    import java.nio.charset.Charset;
    import java.util.Iterator;
    import java.util.Set;
    
    /**
     * @author jiafupeng
     * @desc
     * @create 2021/3/8 10:14
     * @update 2021/3/8 10:14
     **/
    public class NioClientHandler implements Runnable {
    
        private Selector selector;
    
        public NioClientHandler(Selector selector) {
            this.selector = selector;
        }
    
        @Override
        public void run() {
            try {
                for (;;) {
                    int readyChannels = selector.select();
                    if (readyChannels == 0) {continue;}
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator iterator = selectionKeys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey selectionKey = (SelectionKey) iterator.next();
                        iterator.remove();
                        if (selectionKey.isReadable()) {
                            readHandler(selectionKey, selector);
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private void readHandler(SelectionKey selectionKey, Selector selector) throws IOException {
            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            String response = "";
            while (socketChannel.read(byteBuffer) > 0) {
                // 切换buffer为读模式
                byteBuffer.flip();
                // 读取buffer中的内容
                response += Charset.forName("UTF-8").decode(byteBuffer);
            }
            // 将channel再次注册到selector上,监听他的可读事件
            socketChannel.register(selector, SelectionKey.OP_READ);
            // 将服务器端响应信息打印到本地
            if (response.length() > 0) {
                System.out.println(response);
            }
    
        }
    }
    
    4. XXClient
    package com.xu.nio;
    
    import java.io.IOException;
    
    /**
     * @author jiafupeng
     * @desc
     * @create 2021/3/8 10:59
     * @update 2021/3/8 10:59
     **/
    public class XXClient {
    
        public static void main(String[] args) throws IOException {
            new NioClient("jiafupeng").start();
        }
    }
    
    5. YYClient
    package com.xu.nio;
    
    import java.io.IOException;
    
    /**
     * @author jiafupeng
     * @desc
     * @create 2021/3/8 10:59
     * @update 2021/3/8 10:59
     **/
    public class YYClient {
    
        public static void main(String[] args) throws IOException {
            new NioClient("wangdongxu").start();
        }
    }
    

    结果展示

    • 服务器
    • XXClient
    • YYClient

    相关文章

      网友评论

          本文标题:NIO - 多人聊天室Demo代码

          本文链接:https://www.haomeiwen.com/subject/ejnyqltx.html