Loading

NIO-实现聊天室

实现步骤:建立一个服务端和客户端

服务端

1、建立一个服务端

2、创建一个Selector选择器

3、创建一个Channel通道

4、绑定通道的监听端口

5、监听是否有新状态就去处理业务

public class TimServer {

    public static void main(String[] args) throws IOException {
        new TimServer().startServer();
    }

    public void startServer() throws IOException {
        //创建选择器
        Selector selector = Selector.open();
        //创建通道
        ServerSocketChannel ssc = ServerSocketChannel.open();
        //为通道绑定端口
        ssc.bind(new InetSocketAddress(8888));
        //设置为非阻塞通道
        ssc.configureBlocking(false);
        //把通道注册到选择器 加上感兴趣的事件
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器启动成功!");
        //循环监听
        while (true) {
            Set key = selector.selectedKeys();
            Iterator<SelectionKey> iterable = key.iterator();
            int readChannels = selector.select();
            while (iterable.hasNext()) {
                SelectionKey next = iterable.next();
                //移除当前集合的key
                iterable.remove();
                if (next.isAcceptable()) {
                    accept(ssc,selector);

                } else if (next.isReadable()) {
                    readable(selector,next);
                }
            }
        }

    }

    /**
     * 处理连接状态
     * */
    public  void accept(ServerSocketChannel serverSocketChannel,Selector selector) throws IOException {

        //接入ServerSocketChannel
        SocketChannel socketChannel = serverSocketChannel.accept();

        //设置为非阻塞模式
        socketChannel.configureBlocking(false);

        //把channel注册到选择器上
        socketChannel.register(selector,SelectionKey.OP_READ);

        //回复信息
        socketChannel.write(Charset.forName("UTF-8").encode("欢迎来到聊天室~"));
    }


    /**
     * 处理可读状态
     * */
    public void readable(Selector selector,SelectionKey selectionKey) throws IOException {

        //从SelectKey获取就绪的通道
        SocketChannel socketChannel= (SocketChannel) selectionKey.channel();

        //创建buffer
        ByteBuffer buffer=ByteBuffer.allocate(1024);

        //循环读取客户端信息
        StringBuilder stringBuilder=new StringBuilder();
        int readLength = socketChannel.read(buffer);
        if (readLength>0){
            //切换读模式
            buffer.flip();
            //读取内容
            stringBuilder.append(Charset.forName("UTF-8").decode(buffer));
        }
        //把通道注册到选择器上
        socketChannel.register(selector,SelectionKey.OP_READ);

        //广播到其他客户端
       if (stringBuilder.length()>0){
           System.out.println(stringBuilder);
           castClient(selector,socketChannel, String.valueOf(stringBuilder));
       }
    }

    /**
     * 广播到其他客户端
     * */
    public  void  castClient(Selector selector,SocketChannel socketChannel,String message) throws IOException {
        // 获取所有已经接入的channel
        Set<SelectionKey> selectionKeySet=selector.keys();

        //循环所有广播消息
        for (SelectionKey selectionKey : selectionKeySet) {
            //获取每个channel
            Channel tarChannel=selectionKey.channel();
            //不需要给自己发送
            if(tarChannel instanceof  SocketChannel&&tarChannel!=socketChannel){
                ((SocketChannel) tarChannel).write(Charset.forName("UTF-8").encode(message));
            }
        }


    }
}

客户端

public class TimClient {
    public static void main(String[] args) throws IOException {
        new TimClient().startClient("ylc");
    }

    public void startClient(String name) throws IOException {
        //连接服务器
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress( 8888));
        //接收服务端响应
        Selector selector = Selector.open();
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ);

        //创建线程 获取服务器的消息
        new Thread(new ClientThread(selector)).start();
        //向服务器发送消息 控制台输入
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String msg = scanner.nextLine();
            if (msg.length() > 0) {
                socketChannel.write(Charset.forName("UTF-8").encode(name+":"+msg));
            }
        }
    }


}

实现效果:

image-20220403142936425

posted @ 2022-04-16 17:52  炒焖煎糖板栗  阅读(91)  评论(0编辑  收藏  举报