NIO三大组件之 selector

channel的注册中心selector是整个NIO的核心,选择器实现了I/O多路复用。使得单一线程有办法同时对多个socket通道实现监控并及时发现需要处理的IO事件。选择的使用比较简单,主要是三个步骤:

  • 1、将通道注册到一个通道上

    这里创建里一个Selector,并将ServerSocketChanne l注册到selector上

           //创建一个selector对象
            Selector sel = Selector.open();
    
            // 创建severSocketChannel,并设置为非阻塞的模式
            ServerSocketChannel server = sel.provider().openServerSocketChannel();
            server.configureBlocking(false);
    
            //绑定通道到指定的端口
            ServerSocket socket = server.socket();
            socket.bind(new InetSocketAddress(8080));
    
            //向selector注册感兴趣的事件
            server.register(sel, SelectionKey.OP_ACCEPT);
    
  • 2、选择器执行select()方法阻塞获取已经等待就绪的事件

    下面是获取key的示例:

     ByteBuffer buffer = ByteBuffer.allocate(1024);
            try {
                while(true){
                    //这是一个阻塞的动作
                    selector.select();
                    Set<SelectionKey> keys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = keys.iterator();
    
                    while(iterator.hasNext()){
                        SelectionKey key  = iterator.next();
                        //将当前的key 删除掉,防止重复处理
                        iterator.remove();
                        processKey(key,selector, buffer);
                    }
    
    
                }
            }catch (Exception e){
                e.printStackTrace();
            }
    
  • 3、使用获取到的key来反向获取channel,然后进行逻辑处理

    下面是处理key的示例:

     private void processKey(SelectionKey key, Selector selector, ByteBuffer buffer) throws IOException {
            if(key.isAcceptable()){
                ServerSocketChannel serverSocket = (ServerSocketChannel) key.channel();
                SocketChannel accept = serverSocket.accept();
                accept.configureBlocking(false);
                accept.register(selector,SelectionKey.OP_READ,SelectionKey.OP_WRITE);
            }else  if(key.isReadable()){ //读事件
                SocketChannel channel = (SocketChannel) key.channel();
                int len = channel.read(buffer);
    
                if(len > 0 ){
                    buffer.flip();
                    String content = new String(buffer.array());
                    SelectionKey register = channel.register(selector, SelectionKey.OP_WRITE);
                    register.attach(content);
    
                }else{
                    channel.close();
                }
            }else if(key.isWritable()){ //可写事件
                SocketChannel channel = (SocketChannel) key.channel();
                String attach = (String) key.attachment();
                ByteBuffer wrap = ByteBuffer.wrap(("输出内容:" + attach).getBytes());
                //
                channel.write(wrap);
    
            }
        }
    

这里我们需要简单的介绍下SelectionKey 的四个事件:

  • OP_READ:读事件,当前channel发生读事件,将会获得

  • OP_WRITE:写事件。当前channel写事件就绪的时候触发

  • OP_CONNECT:channel连接成功事件。当前channel连接事件发生的时候触发

  • OP_ACCEPT:出现可接入的客户端事件,主要被服务端使用

    下面是这几个事件对应的默认值

    public static final int OP_READ = 1 << 0;


    public static final int OP_WRITE = 1 << 2;


    public static final int OP_CONNECT = 1 << 3;

     */
    public static final int OP_ACCEPT = 1 << 4;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值