Netty源码分析基于主流的Netty4.x版本。
承接上篇的initAndRegister,本篇主要看看bind方法里面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()) {
// CLOSE_ON_FAILURE监听事件是ChannelFuture失败时,执行关闭channel操作
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
进入bind方法,沿着调用链,来到AbstractChannelHandlerContext的bind方法。
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
...
// 向前查找下一个ChannelOutboundHandler类型的处理器,这里是从TailConetxt向前查找
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, null);
}
return promise;
}
按照demo中的设置,当前pipelien中只存在HeadContext,ServerBootstrapAcceptor,TailContext处理器,其中HeadContext即是输入也是输出处理器,ServerBootstrapAcceptor是输入处理器,TailContext为输出处理器。
findContextOutbound方法向前查找的获取的是HeadContext。
继续追踪,来到AbstractChannel的bind方法
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
assertEventLoop();
...
// 目前还未激活,返回false
boolean wasActive = isActive();
try {
// 这里调用原生的channel进行绑定操作,激活成功
doBind(localAddress);
} catch (Throwable t) {
...
return;
}
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
// fireChannelActive方法传递激活事件
// 从header开始依次向ChannelInboundHandler类型的处理器传递
pipeline.fireChannelActive();
}
});
}
// 更新promise为成功状态
safeSetSuccess(promise);
}
当前的channel为NioServerSocketChannel,故查看里面的doBind方法。
protected void doBind(SocketAddress localAddress) throws Exception {
// 实际执行jdk的chanel绑定操作
if (PlatformDependent.javaVersion() >= 7) {
// Backlog这个是设置最多可以进行连接的数量
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
二.传递激活事件
绑定成功之后,isActive方法会返回true,接下来看看传播激活事件的操作
public final ChannelPipeline fireChannelActive() {
// 激活传播首先从HeadContext开始
AbstractChannelHandlerContext.invokeChannelActive(head);
return this;
}
进入HeadContext的invokeChannelActive方法
private void invokeChannelActive() {
// 当前处理器如果已经放入pipeline中返回true
if (invokeHandler()) {
try {
// handler()返回当前的对象即HeadContext
((ChannelInboundHandler) handler()).channelActive(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelActive();
}
}
HeadContext的channelActive主要做两件事:
- 继续传播激活事件
- 设置SelectionKey对OP_ACCEPT感兴趣
public void channelActive(ChannelHandlerContext ctx) {
// 继续传播激活事件
ctx.fireChannelActive();
readIfIsAutoRead();
}
1. 传播激活事件
findContextInbound方法是向查找下一个ChannelInboundHandler类型的处理器。
public ChannelHandlerContext fireChannelActive() {
invokeChannelActive(findContextInbound());
return this;
}
2.设置interestOps
private void readIfIsAutoRead() {
// 这里默认为true
if (channel.config().isAutoRead()) {
channel.read();
}
}
沿着调用链继续走,来到TailContext的read方法。
public ChannelHandlerContext read() {
// 这里还是先前先前查找,按照当前的上下文情况,会找到HeadContext
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeRead();
} else {
Tasks tasks = next.invokeTasks;
if (tasks == null) {
next.invokeTasks = tasks = new Tasks(next);
}
executor.execute(tasks.invokeReadTask);
}
return this;
}
HeadContext的invokeRead只是中转下,最终调用AbstractChannel的beginRead方法。
public final void beginRead() {
...
try {
doBeginRead();
} catch (final Exception e) {
...
}
}
由于当前channel为NioServerSocketChannel,故最终调用AbstractNioChannel的doBeginRead
protected void doBeginRead() throws Exception {
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
// interestOps 这里之前设置0
final int interestOps = selectionKey.interestOps();
// 在实例化NioServerSocketChannel中设置了readInterestOp为SelectionKey.OP_ACCEPT
if ((interestOps & readInterestOp) == 0) {
// 最终对SelectionKey.OP_ACCEPT事件感兴趣
selectionKey.interestOps(interestOps | readInterestOp);
}
}
三. 总结
至此,服务端启动完成,创建了了一个NioServerSocketChannel,关联的selector关注新连接事件。当有新连接来临,将会触发OP_ACCEPT事件。