https://juejin.cn/post/6887395440619651080
接上篇 Netty服务端启动(一)——创建和初始化channel
注册selector
先概括一下,主要做了这几件事
- 设置eventloop(用于绑定线程)
- 调用jdk底层的SelectableChannel类的register方法进行注册
- 触发handler被添加到channel上的回调,触发channel注册成功事件
注册selector的过程就在config().group().register(channel)
这行代码的register
方法里,这个方法最终会调用到AbstractChannel#register
这个方法
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
ObjectUtil.checkNotNull(eventLoop, "eventLoop");
//省略部分代码
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
//省略
}
}
}
可以看到,这里在设置eventloop(用于绑定线程),再看看register0
这个实际注册的方法
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
//neverRegistered初始为true
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
//触发handler被添加到channel上时的回调
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
//传播channel注册成功事件
pipeline.fireChannelRegistered();
if (isActive()) {
//省略
}
} catch (Throwable t) {
//省略
}
}
可以看到,这里调用到了doRegister
方法进行注册,这里会调用到AbstractNioChannel#doRegister
这个方法
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
//javaChannel()返回java底层的SelectableChannel
//注意这里register方法第三参数,将netty的channel绑定到jdk底层的channel作为attachment
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
//省略
}
}
}
可以看到就是调用java底层的方法进行注册
端口绑定
概括一下,主要做了这几件事
- 调用jdk底层的bind方法进行端口绑定
- 触发channelActive事件
- 触发read事件,向selector注册accept事件
端口绑定就在AbstractBootstrap#doBind0
这个方法里
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
这里会最终调用到AbstractChannel#bind
这个方法
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
assertEventLoop();
//省略部分代码
boolean wasActive = isActive();
try {
//调用jdk底层进行绑定
doBind(localAddress);
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
return;
}
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
//发送channelActive事件
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
继续跟进doBind方法,会调用到NioServerSocketChannel#doBind
方法
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
可以看到就是在调用jdk底层的bind方法
fireChannelActive
最终调用到DefaultChannelPipeline#channelActive
这个方法
public void channelActive(ChannelHandlerContext ctx) {
ctx.fireChannelActive();
readIfIsAutoRead();
}
readIfIsAutoRead
方法会调用到AbstractNioChannel#doBeginRead
这个方法
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);
}
}
可以看到,这里是在向selector注册accept事件(可以看看前面NioServerSocketChannel的构造函数里传入了个SelectionKey.OP_ACCEPT)