Reactor Netty HTTP Server接收Connect请求的逻辑
1. 创建 EventLoopGroup
设置 parentGroup 和 childGroup 共用一个 EventLoopGroup ,创建的是 NioEventLoopGroup 实例,包含 8 个 NioEventLoop 实例。
reactor.netty.tcp.TcpServerRunOn#configure(io.netty.bootstrap.ServerBootstrap, boolean, reactor.netty.resources.LoopResources)
static void configure(ServerBootstrap b,
boolean preferNative,
LoopResources resources) {
SslProvider sslProvider = SslProvider.findSslSupport(b);
boolean useNative = preferNative &&
(sslProvider == null || !(sslProvider.sslContext instanceof JdkSslContext));
// parent and children use the sam EventLoopGroup
EventLoopGroup selectorGroup = resources.onServerSelect(useNative);
EventLoopGroup elg = resources.onServer(useNative);
b.group(selectorGroup, elg)
.channel(resources.onServerChannel(elg));
}
2. 创建并初始化 NioServerSocketChannel
在 reactor.netty.tcp.TcpServerBind#bind 方法中会调用 ServerBootStrap.bind() 方法,该方法执行时会创建 NioServerSocketChannel 实例并进行初始化,在初始化 NioServerSocketChannel 时,会添加加 ServerBootstrapAcceptor ChannelHandler。
io.netty.bootstrap.AbstractBootstrap#initAndRegister
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// create NioServerSocketChannel
channel = channelFactory.newChannel();
// 初始化NioServerSocketChannel
init(channel);
} catch (Throwable t) {
// 略
}
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
// 略
return regFuture;
}
3. 将 NioServerSocketChannel 注册到 NioEventLoop
从 NioEventLoopGroup 中获取 NioEventLoop ,将 NioServerSocketChannel 与 NioEventLoop 绑定。如果当前 NioEventLoop 尚未开始运行,则启动线程运行 NioEventLoop.run() 。
启动线程的逻辑 io.netty.util.concurrent.SingleThreadEventExecutor#doStartThread
NioEventLoop的run方法 io.netty.channel.nio.NioEventLoop#run
@Override
protected void run() {
for (;;) {
try {
try {
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.BUSY_WAIT:
// fall-through to SELECT since the busy-wait is not supported with NIO
case SelectStrategy.SELECT:
select(wakenUp.getAndSet(false));
// 略注释
if (wakenUp.get()) {
selector.wakeup();
}
default:
}
} catch (IOException e) {
rebuildSelector0();
handleLoopException(e);
continue;
}
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
if (ioRatio == 100) {
try {
processSelectedKeys();
} finally {
// Ensure we always run tasks.
runAllTasks();
}
} else {
final long ioStartTime = System.nanoTime();
try {
processSelectedKeys();
} finally {
// Ensure we always run tasks.
final long ioTime = System.nanoTime() - ioStartTime;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
}
} catch (Throwable t) {
handleLoopException(t);
}
// Always handle shutdown even if the loop processing threw an exception.
try {
if (isShuttingDown()) {
closeAll();
if (confirmShutdown()) {
return;
}
}
} catch (Throwable t) {
handleLoopException(t);
}
}
}
4. 接收连接请求并处理
连接请求发送到 Netty Http Server 后,NioEventLoop 检测到 NioServerSocketChannel 状态发生变化后 (TODO: 如何监控?) 读取 java.nio.channels.SocketChannel 信息,并将其封装成 io.netty.channel.socket.nio.NioSocketChannel 对象。
信息读取完毕后触发 io.netty.channel.ChannelPipeline#fireChannelRead 方法,最终触发 ServerBootstrapAcceptor ChannelHandler 处理连接请求。
io.netty.bootstrap.ServerBootstrap.ServerBootstrapAcceptor#channelRead
该方法会对 NioSocketChannel 进行设置并将其注册到 child NioEventLoopGroup 。
@Override
@SuppressWarnings("unchecked")
public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel) msg;
child.pipeline().addLast(childHandler);
// 设置channel的操作
setChannelOptions(child, childOptions, logger);
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
try {
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}