netty基础-NIO的selector

2019-01-15  本文已影响0人  cjxz

使用NIO的时候会创建叫号大厅Selector。这是一个单线程不停的循环读取客户端发送过来的请求。然后将客户端的请求保存到SelectionKey里面。

Selector叫号大厅
    selector = Selector.open();
    public static Selector open() throws IOException {
        return SelectorProvider.provider().openSelector();
    }
    //SelectorProvider定义了创建selector、ServerSocketChannel、SocketChannel等方法.采用Java的 Service Provider Interface (SPI) 方式实现
    public static SelectorProvider provider() {
        synchronized (lock) {
            if (provider != null)
                return provider;
            return AccessController.doPrivileged(
                new PrivilegedAction<SelectorProvider>() {
                    public SelectorProvider run() {
                            if (loadProviderFromProperty())
                                return provider;
                            if (loadProviderAsService())
                                return provider;
                            provider = sun.nio.ch.DefaultSelectorProvider.create();
                            return provider;
                        }
                    });
        }
    }
    public static SelectorProvider create() {
        return new KQueueSelectorProvider();
    }
    public AbstractSelector openSelector() throws IOException {
        return new KQueueSelectorImpl(this);
    }

上面是创建Selector的过程。可以看到Selector是new KQueueSelectorProvider生成的,然后调用open()方法,open()方法调用是new KQueueSelectorImpl(this)此处的this是KQueueSelectorProvider对象。在KQueueSelectorImpl这个类里面有几个属性。看名字应该是队列。

    protected int fd0;
    protected int fd1;
    KQueueArrayWrapper kqueueWrapper;
    private int totalChannels;
    private HashMap<Integer, KQueueSelectorImpl.MapEntry> fdMap;
    private boolean closed = false;
    private Object interruptLock = new Object();
    private boolean interruptTriggered = false;
    private long updateCount;

可以看到上面的selector = Selector.open();就是实例一个KQueueSelectorImpl

if (k == null) {
    // New registration
    synchronized (keyLock) {
        if (!isOpen())
            throw new ClosedChannelException();
        k = ((AbstractSelector)sel).register(this, ops, att);
        addKey(k);
    }
}
//AbstractSelectableChannel:这个参数是ServerSocketChannel
//第二个参数是注册事件的类型,有read write accept等
//通过这个方法可以看到register的过程是就是将ServerSocketChannel注册到Selector上面
protected final SelectionKey register(AbstractSelectableChannel var1, int var2, Object var3) {
    if (!(var1 instanceof SelChImpl)) {
        throw new IllegalSelectorException();
    } else {
        SelectionKeyImpl var4 = new SelectionKeyImpl((SelChImpl)var1, this);
        var4.attach(var3);
        Set var5 = this.publicKeys;
        synchronized(this.publicKeys) {
            this.implRegister(var4);
        }

        var4.interestOps(var2);
        return var4;
    }
}

SelectionKeyImpl对象包含了ServerSocketChannel;Selector这样在使用时可以从SelectionKey里面获得Channel,进而读取Channel里面的数据

    //这是SelectionKeyImpl内部的属性
    final SelChImpl channel;  //这个是Channel如果是服务端的话都是ServerSocketChannel
    public final SelectorImpl selector;  //这是Selector
    private int index;
    private volatile int interestOps;
    private int readyOps;

分析到这可以知道在SelectionKey里面是有Channel对象的,如果使用ServerSocketChannel进行register那么Selectionkey里面保存的就是ServerSocketChannel。如果使用SocketChannel进行register那么SelectionKey里面保存的就是SocketChannel。在回到前一篇《netty基础-NIO简单demo》首先是server.register(selector, SelectionKey.OP_ACCEPT);这是如果接收到Accept事件,那么SelectionKey里面存放的是ServerSocketChannel。然后在Accept事件中我们又绑定了read事件。这是使用的client.register(selector,SelectionKey.OP_READ);那么在read事件中获得的Channel就是SocketChannel

上一篇 下一篇

猜你喜欢

热点阅读