美文网首页
NIO中的一些概念理解

NIO中的一些概念理解

作者: 柚子过来 | 来源:发表于2018-03-06 16:24 被阅读0次

    Selector

    一个Selector可以管理多个channel,我们可以创建一个Selector,然后创建channel并将channel注册到Selector:

    Selector Selector=Selector.open();
    channel.configureBlocking(false);
    SelectionKey key= channel.register(selector,SelectionKey,OP_READ); //返回值是一个SelectionKey
    

    从Selector类的源码中可以看出它里面维护了已注册的键集合、已就绪的键集合

    public abstract class SelectorImpl extends AbstractSelector {
    protected Set<SelectionKey> selectedKeys = new HashSet();  //已就绪的键集合。每个channel和Selector都对应一个SelectionKey,所以一个Selector中有一个SelectionKey的集合。
    protected HashSet<SelectionKey> keys = new HashSet();   //已注册的键集合
    private Set<SelectionKey> publicKeys;
    private Set<SelectionKey> publicSelectedKeys;
    ... ...
    }
    

    SelectionKey: 它维护了Selector和channel的注册关系。从源码中可以看出SelectionKey中封装了channel、selector、channel中注册的事件集合、channel已经准备好的事件:

    public class SelectionKeyImpl extends AbstractSelectionKey {
    final SelChImpl channel;
    public final SelectorImpl selector; 
    private int index;
    private volatile int interestOps;  //channel中注册的事件集合。 注意这里虽然是一个int值,但是可以通过与操作确定四个事件的存在与否  
    private int readyOps;  //channel已经准备好的事件
    

    所以:选择器维护注册过的通道的集合,并且这种注册关系都被封装在SelectionKey当中,又因为一个Selector管理着多个channel,所以Selector中封装了SelectionKey的集合,包括已注册的和注册并已就绪的。

    Selector的select()方法返回的是已就绪的channel数量,它会阻塞直至有通道就绪才会返回。所以服务器只需要一个线程通过轮询并调用select方法监听是否有事件发生。如果有的话,直接迭代selectedKeys进行处理就行了:

     private void listener() throws Exception {
        while (true) {
            int n = selector.select();
            if (n == 0) {
                continue;
            }
            Iterator<SelectionKey> ite = selector.selectedKeys().iterator();
            while (ite.hasNext()) {
                SelectionKey key = ite.next();
                //a connection was accepted by a ServerSocketChannel.
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel channel = server.accept();   //等待客户端连接
                    registerChannel(selector, channel, SelectionKey.OP_READ);  //连接成功后像channel注册读事件
                    remoteClientNum++;
                    System.out.println("online client num="+remoteClientNum);
                    replyClient(channel);
                }
                //a channel is ready for reading
                if (key.isReadable()) {
                    readDataFromSocket(key);
                }
    
                ite.remove();//must
            }
    
        }
    }
    

    而在NIO中的操作就是调用channel的read和write方法,这两个方法将数据读写到Buffer。

      private void replyClient(SocketChannel channel) throws IOException {
        byteBuffer.clear();
        byteBuffer.put("hello client!\r\n".getBytes());
        byteBuffer.flip();
        channel.write(byteBuffer);
    }
    

    Buffer

    flip(): NIO的Buffer机制中可以通过该方法来进行Buffer的读模式与写模式的切换,相当于一个Buffer实现了IO中的InputStream和OutputStream的功能。
    所以是将Buffer中的数据写到channel和从channel读取数据到Buffer两个操作。其实write(Buffer)操作最终是将Buffer缓冲区数据的数据写到内存中,然后再通过网络传输,所以这里就分了Buffer和DirectBuffer等不同的Buffer,像DirectBuffer本身就是分配的堆外内存,所以数据直接放进去就行了,而普通的Buffer是堆内存储的,所以就需要多一个从堆内拷贝到堆外内存的过程:

    static int read(FileDescriptor var0, ByteBuffer var1, long var2, NativeDispatcher var4) throws IOException {
        if (var1.isReadOnly()) {
            throw new IllegalArgumentException("Read-only buffer");
        } else if (var1 instanceof DirectBuffer) {
            return readIntoNativeBuffer(var0, var1, var2, var4);      //直接调用的native方法将数据放到堆外内存
        } else {
            ByteBuffer var5 = Util.getTemporaryDirectBuffer(var1.remaining());  //先分配堆外内存
    
            int var7;
            try {
                int var6 = readIntoNativeBuffer(var0, var5, var2, var4);  //再将Buffer数据拷贝过去
                var5.flip();
                if (var6 > 0) {
                    var1.put(var5);
                }
    
                var7 = var6;
            } finally {
                Util.offerFirstTemporaryDirectBuffer(var5);
            }
    
            return var7;
        }
    }
    

    相关文章

      网友评论

          本文标题:NIO中的一些概念理解

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