五Netty源码分析--3Bootstrap.bind--下
五Netty源码分析--3Bootstrap.bind--下
TAG1.3.1.1.3 register0
AbstractChannel
private void register0(ChannelPromise promise) {
try {
// 检查channel是否是open状态(因为在register过程,eventloop外的线程可以执行关闭channel的操作)
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered; //是否第一次注册
//REGI1 doRegister
doRegister();
neverRegistered = false;
registered = true;
//REGI2 pipeline.invokeHandlerAddedIfNeeded()---
//触发添加入channel.pipeline上的handlercontext的add操作,然后handler链,可以处理event事件
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
//REGI3 pipeline.fireChannelRegistered()
pipeline.fireChannelRegistered();
//REGI4 isActive
//active状态:只有channel第一次注册时,才会pipeline.fireChannelActive(当底层socket为open或connect时为active)
//(避免当前channel再次注册时,会fire多个channel的active操作)
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);
}
}
这里,可以看到此时,Netty的NioServerSocketChannel包装了NIO原生ServerSocketChannelImpl类,并且在初始化时,设置channel感兴趣的事件为ACCEPT。
REGI1 doRegister(NIO原生channel注册到NioEventLoop)
AbstractNioChannel
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
//REGI1.1 javaChannel() -----获取原生NIOchannel
//REGI1.2 channel.register------注册channel到selector上
//将NIO原生channel注册到原生selector上
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected = true;
} else {
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
//REGI1.1 javaChannel()
返回Netty的NioServerSocketChannel包装的NIO原生ServerSocketChannelImpl类。
//REGI1.2 channel.register
AbstractNioChannel
//REGI1.1 javaChannel() -----获取原生NIOchannel
//REGI1.2 channel.register------注册channel到selector上
//将NIO原生channel注册到原生selector上
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
原生channel.register(0)的原因:
这里原生channel注册到selector上,但是,关注的事件为0(就是不设置关注事件)。因为Netty的NioServerSocketChannel包裹了NIO原生channel,并且已经设置了ACCEPT关注事件,只关注client端的连接,当Netty的channel获取连接就绪channel后,需要对当前channel注册事件,这时获取原生NIOchannel,并注册需要关注的事件。所以,这里先设置原生NIO不关注事件,在后续操作中再设置关注。
AbstractSelectableChannel
public final SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException {
synchronized (regLock) {
if (!isOpen())
throw new ClosedChannelException();
//检查validOps()有效事件,是否不包含ops
if ((ops & ~validOps()) != 0)
throw new IllegalArgumentException();
if (blocking)
throw new IllegalBlockingModeException();
//找到当前channel的keys[],非null,且key.selector==sel的SelectionKey
SelectionKey k = findKey(sel);
//如果k不为null,表示当前channel在selector上注册过
if (k != null) {
//设置k关注的事件
k.interestOps(ops);
//SelectionKey的attach为当前nioServerSocketChannel
k.attach(att);
}
//如果k为null,表示当前channel尚未在selector上注册过,需要新注册
if (k == null) {
// New registration
synchronized (keyLock) {
if (!isOpen())
throw new ClosedChannelException();
//REGI1.2.1 selector.register
//重新将原生channel注册到selector上
k = ((AbstractSelector)sel).register(this, ops, att);
addKey(k); //将k加入当前channel对应的key[]集合中
}
}
return k;
}
}
//REGI1.2.1 selector.register(原生channel注册到原生selector)
SelectorImpl
protected final SelectionKey register(AbstractSelectableChannel var1, int var2, Object var3) {
if (!(var1 instanceof SelChImpl)) {
throw new IllegalSelectorException();
} else {
//创建selectionkey(包括channel和selector的关系)
SelectionKeyImpl var4 = new SelectionKeyImpl((SelChImpl)var1, this);
//将NIOchannel加入selectionkey的attach上
var4.attach(var3);
synchronized(this.publicKeys) {
this.implRegister(var4);
}
//设置关注事件var2
var4.interestOps(var2);
return var4;
}
}
REGI2 pipeline.invokeHandlerAddedIfNeeded()---执行handlerAdd方法
DefaultChannelPipeline
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
//如果channel第一次注册到nioeventloop时
if (firstRegistration) {
firstRegistration = false;
//目前,channelpipeline已经注册到eventloop,现在需要在registration完成之前,回调channelhandlers的add方法
callHandlerAddedForAllHandlers();
}
}
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
synchronized (this) {
assert !registered;
// 设置channel已经注册到nioeventloop上
registered = true;
//PendingHandlerCallback需要执行handler.add的任务task链的head
pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
// 将this的callback设为null,使其能被GC
this.pendingHandlerCallbackHead = null;
}
// This must happen outside of the synchronized(...) block as otherwise handlerAdded(...) may be called while
// holding the lock and so produce a deadlock if handlerAdded(...) will try to add another handler from outside
// the EventLoop.
PendingHandlerCallback task = pendingHandlerCallbackHead;
/**……………………………………………………………………………………轮询执行pendingTask中ctx的add操作…………………………………………………………………………………………………… */
while (task != null) {
//REGI2.1 PendingHandlerCallback.execute
task.execute();
task = task.next;
}
}
其中,PendingHandlerCallback为DefaultChannelPipeline的内部类
此时,执行到这里时,DefaultChannelPipeline中pendingHandlerCallbackHead内包裹的handlerContext,为添加入
//REGI2.1 PendingHandlerCallback.execute
DefaultChannelPipeline
private final class PendingHandlerAddedTask extends PendingHandlerCallback {
PendingHandlerAddedTask(AbstractChannelHandlerContext ctx) {
super(ctx);
}
@Override
public void run() {
callHandlerAdded0(ctx);
}
@Override
void execute() {
EventExecutor executor = ctx.executor();
//保证在nioeventloop所在线程中执行callHandlerAdded0操作
if (executor.inEventLoop()) {
//REGI2.1.1 callHandlerAdded0 调用handler的add操作
callHandlerAdded0(ctx);
} else {
try {
executor.execute(this);
} catch (RejectedExecutionException e) {
if (logger.isWarnEnabled()) {
logger.warn(
"Can't invoke handlerAdded() as the EventExecutor {} rejected it, removing handler {}.",
executor, ctx.name(), e);
}
atomicRemoveFromHandlerList(ctx);
ctx.setRemoved();
}
}
}
}
//REGI2.1.1 callHandlerAdded0--->TAG1.2.1.3
DefaultChannelPipeline
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
//REGI2.1.1.1 handlerContext.callHandlerAdded
//调用handlercontext的handleradd操作
ctx.callHandlerAdded();
} catch (Throwable t) {
boolean removed = false;
try {
atomicRemoveFromHandlerList(ctx);
ctx.callHandlerRemoved();
removed = true;
} catch (Throwable t2) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to remove a handler: " + ctx.name(), t2);
}
}
if (removed) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; removed.", t));
} else {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; also failed to remove.", t));
}
}
}
//REGI2.1.1.1 handlerContext.callHandlerAdded--->TAG1.2.1.3.1
AbstractChannelHandlerContext
final void callHandlerAdded() throws Exception {
//首先设置handlerContext的状态为ADD-COMPLETE
if (setAddComplete()) {
//HanAdd1 handler().handlerAdded(this)
handler().handlerAdded(this);
}
}
final boolean setAddComplete() {
for (;;) {
int oldState = handlerState;
if (oldState == REMOVE_COMPLETE) {
return false;
}
// 设置状态为ADD_COMPLETE
if (HANDLER_STATE_UPDATER.compareAndSet(this, oldState, ADD_COMPLETE)) {
return true;
}
}
}
//HanAdd1 handler().handlerAdded(this)(调用handler.handlerAdded)--channelInitializer的执行
public interface ChannelHandler {
/**
* Gets called after the {@link ChannelHandler} was added to the actual context and it's ready to handle events.
*/
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
当handler被真正添加入handlerContext后,会调用channelHandler.handlerAdded操作,之后,handler才能真正的准备好处理事件。
对于ChannelInitializer实现类来说:
ChannelInitializer
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
//HanADD1.1 ChannelInitializer.initChannel
//初始化channel---channelInitializer类的initChannel方法,会将childhandler添加入channelPipeline中
if (initChannel(ctx)) {
//HanAdd1.2 removeState---略
// We are done with init the Channel, removing the initializer now.
removeState(ctx);
}
}
}
//HanADD1.1 ChannelInitializer.initChannel(跳过)
ChannelInitializer
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.add(ctx)) { // Guard against re-entrance.
try {
//HanADD1.1.1 initChannel((C) ctx.channel())
initChannel((C) ctx.channel());
} catch (Throwable cause) {
// Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
// We do so to prevent multiple calls to initChannel(...).
exceptionCaught(ctx, cause);
} finally {
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
//HanAdd1.1.2 pipeline.remove(channelInitializer)
//将ChannelInitializer从pipeline中移除
pipeline.remove(this);
}
}
return true;
}
return false;
}
//HanADD1.1.1 initChannel((C) ctx.channel())---(serverBootstrap匿名channelInitializer,创建并添加ServerBootstrapAcceptor)
ctx.channel为handlerContext所绑定的channel;
这里,initChannel方法会执行ServerBootstrap中创建匿名类ServerBootstrap$1的initChannel方法。
config.handler获取向ServerBootstrap.handler(LoggingHandler)配置的handler,加入pipeline中。
//将runnable转换为task,加入NioEventLoop的任务队列中
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
将pipeline.addLast(ServerBootstrapAcceptor)的操作,作为task,加入NioEventLoop的任务队列中---addTask(task)中。当nioeventloop绑定线程执行时,wakeup操作,唤醒nioeventloop内阻塞select操作,执行任务队列中任务。详见[StartThread1 NioEventLoop.run](#StartThread1 NioEventLoop.run)
该执行过程,会向pipeline中添加ServerBootstrapAcceptor类,其中currentChildHandler为Server启动程序中,添加的自定义channelInitializer类
//HanAdd1.1.2 pipeline.remove(channelInitializer)--略
移除自定义的ChannelInitializer。
DefaultChannelPipeline
@Override
public final ChannelPipeline remove(ChannelHandler handler) {
remove(getContextOrDie(handler));
return this;
}
public final ChannelPipeline remove(ChannelHandler handler) {
remove(getContextOrDie(handler));
return this;
}
private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
assert ctx != head && ctx != tail;
synchronized (this) {
atomicRemoveFromHandlerList(ctx);
// If the registered is false it means that the channel was not registered on an eventloop yet.
// In this case we remove the context from the pipeline and add a task that will call
// ChannelHandler.handlerRemoved(...) once the channel is registered.
if (!registered) {
callHandlerCallbackLater(ctx, false);
return ctx;
}
EventExecutor executor = ctx.executor();
if (!executor.inEventLoop()) {
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerRemoved0(ctx);
}
});
return ctx;
}
}
callHandlerRemoved0(ctx);
return ctx;
}
这个逻辑,同TAG1.2.1 ChannelPipeline.addLast逻辑相同,省略
REGI3 pipeline.fireChannelRegistered()---pipeline上链式触发
触发channel绑定的pipeline.fireChannelRegistered()方法,触发pipeline上的handler链上的处理链。(REGI2过程,执行过channel.pipeline上context.add操作后,handler此时可以处理event事件)。
AbstractChannel
pipeline.fireChannelRegistered();
DefaultChannelPipeline
@Override
public final ChannelPipeline fireChannelRegistered() {
//pipeline中保存context链中的head和tail,inbound操作,从head开始调用
AbstractChannelHandlerContext.invokeChannelRegistered(head);
return this;
}
AbstractChannelHandlerContext
static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
//context中链式调用
next.invokeChannelRegistered();
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRegistered();
}
});
}
}
可知,此时,server端channePipeline上handlerContext链如下:
HeadContext------>LoggingHandler------>TailContext
AbstractChannelHandlerContext
private void invokeChannelRegistered() {
if (invokeHandler()) {
try {
//(ChannelInboundHandler) handler()获取的是pipeline
((ChannelInboundHandler) handler()).channelRegistered(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRegistered();
}
}
DefaultChannelPipeline
@Override
public void channelRegistered(ChannelHandlerContext ctx) {
invokeHandlerAddedIfNeeded(); //调用handleradd
ctx.fireChannelRegistered();
}
递归调用:context.fireXXX,其内的findContextInbound遍历context中对应事件的handler
AbstractChannelHandlerContext
@Override
public ChannelHandlerContext fireChannelRegistered() {
//findContextInbound(MASK_CHANNEL_REGISTERED)实现context链中的遍历,找到关注registered的handlerContext
invokeChannelRegistered(findContextInbound(MASK_CHANNEL_REGISTERED));
return this;
}
AbstractChannelHandlerContext
static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRegistered();
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRegistered();
}
});
}
}
AbstractChannelHandlerContext
private void invokeChannelRegistered() {
if (invokeHandler()) {
try {
//调用实际handler的channelRegistered方法
((ChannelInboundHandler) handler()).channelRegistered(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRegistered();
}
}
LoggingHandler
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
if (logger.isEnabled(internalLevel)) {
logger.log(internalLevel, format(ctx, "REGISTERED"));
}
//handlercontext的链式调用
ctx.fireChannelRegistered();
}
以上的pipeline上的链式context执行流程如下:
详细过程见[17.5.3.3 AbstractChannelHandlerContext.fireChannelRead流程](#17.5.3.3 AbstractChannelHandlerContext.fireChannelRead流程)
REGI4 isActive(channel已经注册过,active状态的处理)
1 channel已经注册到NioEventLoop中---状态为registered
2 然后判断channel是否为active:
2.1 如果channel第一次注册,执行pipeline.fireChannelActive;
2.2 如果channel不是第一次注册,执行beginRead,准备读
TAG2 ChannelFuture.channel
返回server端parentchannel。
channeFutrue和channelPromise,详看netty组件。
TAG3 doBind0--绑定端口
在server端,regFuture尚未完成,因此执行channelFuture的异步机制监听,等待任务完成时,执行自定义operationComplete内的doBind0()绑定。
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() {
//当channel初始化并注册到nioeventloop成功后,会执行channe绑定端口bind操作
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
AbstractChannel
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return pipeline.bind(localAddress, promise);
}
DefaultChannelPipeline
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
//outbound类型的bind,从tailContext开始
return tail.bind(localAddress, promise);
}
AbstractChannelHandlerContext
@Override
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
if (isNotValidPromise(promise, false)) {
// cancelled
return promise;
}
//TAG3.1 findContextOutbound(MASK_BIND)
final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
//TAG3.2 context.invokeBind
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, null);
}
return promise;
}
TAG3.1 findContextOutbound(MASK_BIND)
找到bind事件的handlerContext。
AbstractChannelHandlerContext
private AbstractChannelHandlerContext findContextOutbound(int mask) {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.prev;
//当不包含mask(BIND)感兴趣事件时,遍历下一个handlerContext
} while ((ctx.executionMask & mask) == 0);
return ctx;
}
遍历找到HeadContext,其进行实际的bind(localAddress)
TAG3.2 context.invokeBind
AbstractChannelHandlerContext
private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
if (invokeHandler()) {
try {
((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
} else {
bind(localAddress, promise);
}
}
DefaultChannelPipeline--->HeadContext
@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
//TAG3.2.1 unsafe.bind
unsafe.bind(localAddress, promise);
}
//TAG3.2.1 unsafe.bind
AbstractChannel-->AbstractUnsafe
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
assertEventLoop();
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
// See: https://github.com/netty/netty/issues/576
if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) &&
localAddress instanceof InetSocketAddress &&
!((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() &&
!PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
// Warn a user about the fact that a non-root user can't receive a
// broadcast packet on *nix if the socket is bound on non-wildcard address.
logger.warn(
"A non-root user can't receive a broadcast packet if the socket " +
"is not bound to a wildcard address; binding to a non-wildcard " +
"address (" + localAddress + ") anyway as requested.");
}
//判断channel是否被active激活(此时socket尚未open,因此为false)
boolean wasActive = isActive();
try {
//BIND1 doBind(localAddress)
doBind(localAddress);
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
return;
}
//BIND2 pipeline.fireChannelActive()
//当channel的socket刚刚被active时。然后再执行fireChannelActive
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
BIND1 doBind(localAddress)
NioServerSocketChannel
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
//获取NIO原生serverSocketChannel对象,执行bind绑定端口和地址
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
BIND2 pipeline.fireChannelActive()---channel绑定端口后active激活
执行pipeline上的触发channel的active激活。
TAG4 channelfuture异步机制--todo
channelFuture.addListener,是netty实现异步操作的核心。