OP_ACCEP注册
首先,ServerSocketChannel创建时就指定感兴趣事件OP_ACCEPT;然后,在注册阶段,直接向Selector注册OP_ACCEPT;
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
OP_READ注册
首先,SocketChannel创建时就指定感兴趣事件OP_READ;然后,在注册阶段,直接向Selector注册OP_READ;
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
super(parent, ch, SelectionKey.OP_READ);
}
OP_WRITE注册
Flush时,如果ChannelOutboundBuffer的数据没有全部写入Channel的发送缓冲区,则注册OP_WRITE,如NioSocketChannel的doWrite()方法所示。当Channel的发送缓冲区可写之后,产生OP_WRITE事件,处理逻辑是:再次调用flush方法,继续将ChannelOutboundBuffer的数据写入Channel。
for (int i = writeSpinCount - 1; i >= 0; i --) {
int localFlushedAmount = doWriteBytes(buf);
if (localFlushedAmount == 0) {
setOpWrite = true;
break;
}
flushedAmount += localFlushedAmount;
if (!buf.isReadable()) {
done = true;
break;
}
}
protected final void incompleteWrite(boolean setOpWrite) {
// Did not write completely.
if (setOpWrite) {
setOpWrite();
} else {
// Schedule flush again later so other tasks can be picked up in the meantime
Runnable flushTask = this.flushTask;
if (flushTask == null) {
flushTask = this.flushTask = new Runnable() {
@Override
public void run() {
flush();
}
};
}
eventLoop().execute(flushTask);
}
}
// Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
// Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
ch.unsafe().forceFlush();
}
OP_WRITE注销
Flush时,如果ChannelOutboundBuffer的数据全部写入Channel的发送缓冲区,则取消OP_WRITE的注册,如NioSocketChannel的doWrite()方法所示:
OP_WRITE特殊性说明
OP_WRITE表示Channel的发送缓冲区可写,如果OP_WRITE一直被注册,大部分情况下Channel是空闲的,产生大量的OP_WRITE事件;只有在Flush时,ChannelOutboundBuffer中的数据没有全部写入Channel的发送缓冲区,才会关心Channel的发送缓冲区何时变为可写。
参考: