NOTE
2.75 4.服务端口绑定
调用 bind - doBind - initAndRegister - channelFactory.newChannel() - init(channel) - ChannelFuture regFuture = config().group().register(channel); - doB
这是历史学习笔记,可能存在过时或不完整的理解。
调用
bind
- doBind
- initAndRegister
- channelFactory.newChannel()
- init(channel)
- ChannelFuture regFuture = config().group().register(channel);
- doBind0(regFuture, channel, localAddress, promise);我们重点看这个
AbstractBootstrap
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (regFuture.isSuccess()) {
//调用AbstractChannel的bind
//接着调用DefaultChannelPipeline的bind
//再调用AbstractChannelHandlerContext#bind
//最后来到AbstractChannel.AbstractUnsafe#bind
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
AbstractUnsafe
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
//调用jdk底层绑定地址
//javaChannel().bind(localAddress, config.getBacklog());
doBind(localAddress);
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
//调用pipeline上所有InboundHandler的channelActive方法
//第一个handler为DefaultChannelPipeline.HeadContext
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
io.netty.channel.DefaultChannelPipeline.HeadContext#channelActive
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
readIfIsAutoRead();//关键
//会调用channel.read->pipeline.read->tail.read->ChannelOutboundHandler.read->
//io.netty.channel.AbstractChannel.AbstractUnsafe#beginRead
//->io.netty.channel.nio.AbstractNioChannel#doBeginRead
}
AbstractNioChannel
protected void doBeginRead() throws Exception {
// Channel.read() or ChannelHandlerContext.read() was called
//拿到selectKey
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
//增加读事件:accpet事件
selectionKey.interestOps(interestOps | readInterestOp);
}
}
