上一篇文章《netty源码阅读之客户端新连接之分配线程并注册selector》这里,我们最后分析到AbstractChannel的register0()的代码:
private void register0(ChannelPromise promise) {
try {
// check if the channel is still open as it could be closed in the mean time when the register
// call was outside of the eventLoop
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
// Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
// user may already fire events through the pipeline in the ChannelFutureListener.
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
// Only fire a channelActive if the channel has never been registered. This prevents firing
// multiple channel actives if the channel is deregistered and re-registered.
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// This channel was registered before and autoRead() is set. This means we need to begin read
// again so that we process inbound data.
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
} catch (Throwable t) {
// Close the channel directly to avoid FD leak.
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
注册完成之后isActive()已经为true了,然后我们这个是第一次注册(新连接已经接入并且注册到selector上面了所以isActive()为true),所以会进入到pipeline.fireChannelActive().点击进入,和服务端一样,最后会进入HeadContext的channelActive函数:
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
readIfIsAutoRead();
}
ctx.fireChannel就是继续传播事件,readInfIsAutoRead()就是注册读事件,进入:
private void readIfIsAutoRead() {
if (channel.config().isAutoRead()) {
channel.read();
}
}
channel.config().isAutoRead()就是是否自动阅读,默认是自动读取的。所以继续不停进入来到HeadContext的read方法:
@Override
public void read(ChannelHandlerContext ctx) {
unsafe.beginRead();
}
继续进入AbstractNioChannel的doBeginRead():
@Override
protected void doBeginRead() throws Exception {
// Channel.read() or ChannelHandlerContext.read() was called
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);
}
}
在这一篇文章《netty源码阅读之客户端新连接之分配线程并注册selector》的最后,我们注册进去的事件是0,也就是什么也不注册,所以这里final int interestOps = selectionKey.interestOps();返回0。
然后readInterestOp这个值又是什么呢,我们回顾《netty源码阅读之客户端新连接之创建NioSocketChannel》第一段,创建AbstractNioByteChannel的时候,传入了SelectionKey.OP_READ,然后父类AbstractNioChannel的方法里面
this.readInterestOp = readInterestOp;
赋值了
SelectionKey.OP_READ。所以readInterestOp就是赋值的值,查看源码是1。0&1是0,所以就相当于把readInterestOp这个读事件,注册进去了(在原来没有读事件的基础上,并且在不修改之前已有事件的基础上,把OP_READ事件注册进去)。
perfect。