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

Selector.open();
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
-
server.register(selector, SelectionKey.OP_ACCEPT);
register的过程就是注册SelectionKey
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