对于启动类,有以下这种简单的方式:
ServerBootstrap serverBootstrap = new ServerBootstrap();
NioEventLoopGroup boss = new NioEventLoopGroup();
NioEventLoopGroup worker = new NioEventLoopGroup();
serverBootstrap
.group(boss, worker)
.channel(NioServerSocketChannel.class)
.childHandler(new TestServerChannelInitializer())
.bind(1234);
比较诡异的有以下(伪代码):
//第一种
serverBootstrap.group(boss,worker).bind(1234);
serverBootstrap.bind(1235);
serverBootstrap.bind(1236);
//第二种
serverBootstrap.group(boss,boss);
//第三种
serverBootstrap1.group(boss,worker);
serverBootstrap2.group(boss,worker);
//这样的组合剩下的脑补
对于这样的代码,可以有很多种。其实NioEventLoopGroup对应于一个线程池,这个线程池里的NioEventLoop是单线程的,NioEventLoop中可以对应多个Channel,每个Channel对应于1个端口。而ServerBootstrap其实仅仅是把boss,worker,NioServerSocketChannel组装起来。组装起来后获取的是ServerBootstrap的引用,然后bind后才会获取到一个ChannelFuture。而对于boss和worker来说,这样的复用,也只是线程池这个概念被2个地方使用了而已。
//代码来自AbstractBootstrap
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);//这一步会把新建的channel放入worker中。
} catch (Throwable t) {
if (channel != null) {
// channel can be null if newChannel crashed (eg SocketException("too many open files"))
channel.unsafe().closeForcibly();
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
//这一步会把channel放入boss中。
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
// If we are here and the promise is not failed, it's one of the following cases:
// 1) If we attempted registration from the event loop, the registration has been completed at this point.
// i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
// 2) If we attempted registration from the other thread, the registration request has been successfully
// added to the event loop's task queue for later execution.
// i.e. It's safe to attempt bind() or connect() now:
// because bind() or connect() will be executed *after* the scheduled registration task is executed
// because register(), bind(), and connect() are all bound to the same thread.
return regFuture;
}
网友评论