文章目录
前言: ServerBootstrapAcceptor类似于reactor的acceptor事件处理器 负责客户端channel向选择器的注册
ServerBootstrapAcceptor处理客户端注册
原理图
- 蓝色表示ServerSocket接收读事件[客户端注册]
- 黄色表示为NioSocketChannel注册到SelectKey
- 注册事件(register0)交给WorkerEventLoop
源码分析一channelRead
- 获取客户端NioSocketChannel
- 为NioSocketChannel配置用户编写的ChannelInitializer
- 向workerGroup的其中一个EventLoop注册NioSocketChannel
private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
此类为NioSocketChannel
final Channel child = (Channel) msg;
/*
b.group(bossGroup, workerGroup)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(handler);
}
});
*/
用户配置的ChannelInitializer初始化handler
child.pipeline().addLast(childHandler);
NioSocketChannel的配置kv集合中 初始化Options
setChannelOptions(child, childOptions, logger);
NioSocketChannel的属性kv集合中 初始化Attrs
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
向workerGroup的其中一个EventLoop注册NioSocketChannel
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
}
}
- childGroup通过EventExecutorChooser轮询获取下一个eventLoop进行NioSocketChannel注册
public ChannelFuture register(Channel channel) {
childGroup通过轮询获取下一个eventLoop进行NioSocketChannel注册
return next().register(channel);
}
-
eventLoop调用unsafe执行注册
public ChannelFuture register(final Channel channel, final ChannelPromise promise) {
交给unsafe执行注册
channel.unsafe().register(this, promise);
return promise;
}
- 将register0注册任务添加到eventLoop,进行异步注册
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
添加任务
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
}
}
register0注册客户端到selector
原理图
源码分析
- javachannel注册selector (没有注册前通道可以进行读写但还没有交给selector管理)
- 将ChannelInitializer.init中编写的业务handler添加到pipeline,同时删除将ChannelInitializer本身
- 触发注册事件
- 触发激活通知
private void register0(ChannelPromise promise) {
boolean firstRegistration = neverRegistered;
javachannel注册selector 此时的通道可以进行读写但还没有交给selector管理
doRegister();
neverRegistered = false;
registered = true;
将ChannelInitializer.init中编写的业务handler添加到pipeline
同时删除将ChannelInitializer本身
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
触发注册事件
pipeline.fireChannelRegistered();
if (isActive()) {
if (firstRegistration) {
触发激活通知
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
}
- register0执行前后NioSocketChannel的handler结构如下:
- 业务handler添加完毕会删除ChannelInitializer
总结
- 客户端连接到达后通过ServerBootstrapAcceptor完成channel向selectKey的注册
- 同时初始化NioSocketChannel的handler链[一般每次初始化都是新建,但也存在@Sharable共享用法]
扩展点一netty与java之间channel关联关系
- nettyChannel有两个属性分别表示javachannel和selectKey
- selectkey的附件中包含nettyChannel
- java层面持有nettychannel领域交互类,netty层面持有javachannel,selectKey领域交互类
扩展点一channel与线程关系
- 一个EventLoop逻辑上一个线程(不同版本实现不同)
- 一个EventLoop只会有一个线程处理selector
- 一个EventLoop的selector可能会注册多个Channel
- 一个channel只会注册一个selector