3-2 服务端 ChannelFuture 的创建
一 问题
1. 服务端socket在哪里初始化
2. 在哪里accept连接
二 Netty启动Channel过程
1. 创建服务端Channel
2. 初始化服务端Channel
3.注册selector
4.端口绑定
三 Netty启动Channel过程: 创建服务端 ChannelFuture
1. AbstractBootstrap#bind(int) 为服务端端口绑定的入口
public ChannelFuture bind(int inetPort) { return bind(new InetSocketAddress(inetPort)); }
这个 bind 方法会执行到 AbstractBootstrap#doBind 方法
2. 进入 AbstractBootstrap#doBind 方法
private ChannelFuture doBind(final SocketAddress localAddress) { //初始化并创建一个 ChannelFuture final ChannelFuture regFuture = initAndRegister(); final Channel channel = regFuture.channel(); if (regFuture.cause() != null) { return regFuture; } // if (regFuture.isDone()) { // At this point we know that the registration was complete and successful. // ChannelFuture 初始化并注册完成,创建一个 ChannelPromise 对象 ChannelPromise promise = channel.newPromise(); //调用 doBind0 绑定端口 doBind0(regFuture, channel, localAddress, promise); return promise; } else { // ChannelFuture 未完成注册的过程,ChannelPromise 添加 一个 ChannelFutureListener 监听,等 ChannelFuture 完成注册时会自动通知监听, // 监听会再调用 doBind0 绑定端口 // Registration future is almost always fulfilled already, but just in case it's not. final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel); regFuture.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { Throwable cause = future.cause(); if (cause != null) { // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an // IllegalStateException once we try to access the EventLoop of the Channel. promise.setFailure(cause); } else { // Registration was successful, so set the correct executor to use. // See https://github.com/netty/netty/issues/2586 promise.registered(); doBind0(regFuture, channel, localAddress, promise); } } }); return promise; } }
doBind 会先调用 initAndRegister() 初始化并注册 ChannelFuturedoBind0 再绑定端口
3. 进入 AbstractBootstrap.initAndRegister() 方法
/** * 初始化并创建一个 ChannelFuture * @return */ final ChannelFuture initAndRegister() { Channel channel = null; try { //STEP1 先创建一个 channel /** * 调用 channelFactory 工厂创建一个 channel,具体要创建的Channel类型在调用 * {@link AbstractBootstrap#channel(java.lang.Class)} 方法时传入,再通过反射创建具体 channel 实例 */ channel = channelFactory.newChannel(); //STEP2 初始化 channel init(channel); } 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); } // STEP3 channel 注册到 eventLoop 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; }
AbstractBootstrap.initAndRegister() 方法主要有3步,
- STEP1: 调用channelFactory.newChannel() 创建channel,这里创建 channel 的具体方法就是采用反射将 AbstractBootstrap#channel 传入的类型创建一个 channel 实例,Netty 服务端具体的类型为 NioServerSocketChannel,具体 NioServerSocketChannel 创建流程请查看 https://www.cnblogs.com/programmlover/p/14826788.html
- STEP2:调用 init 方法初始化 channel
- STEP3:将 channel 注册到 EventLoopGroup, 这里注册的 EventLoopGroup 是传入的 bossGroup,具体注册流程请查看 https://www.cnblogs.com/programmlover/p/11924879.html
四 init() 初始化流程
进入 ServerBootstrap.init() 方法
/**
* 服务端 channel 初始化流程
* @param channel
*/
@Override
void init(Channel channel) {
//将 options 和 attributes 保存到 EMPTY_OPTION_ARRAY 和 EMPTY_ATTRIBUTE_ARRAY
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
//获取 ServerSocketChannel 的 pipeline
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions;
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(EMPTY_OPTION_ARRAY);
}
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY);
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
//获取 channelHandler并先添加到 pipeline, 这一个 channelHandler 是在调用 AbstractBootstrap.handler(ChannelHandler) 时设置的
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
//将 channel, childGroup,childHandler,currentChildOptions,currentChildAttrs 等属性
// 封装成一个 ServerBootstrapAcceptor 并添加到 pipeline
// ServerBootstrapAcceptor 作用是每次在 accept 一个新的连接时都会使用这些属性进行配置
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
ServerBootstrap.init() 方法会先设置 options 和 attributes,然后将 channelHandler 添加到 pipeline,最后将 channel, childGroup,childHandler,currentChildOptions,currentChildAttrs 等属性封装成一个 ServerBootstrapAcceptor 并添加到 pipeline,ServerBootstrapAcceptor 作用是每次在 accept 一个新的连接时都会使用这些属性进行配置

浙公网安备 33010602011771号