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步,

  1. STEP1: 调用channelFactory.newChannel() 创建channel,这里创建 channel 的具体方法就是采用反射将 AbstractBootstrap#channel 传入的类型创建一个 channel 实例,Netty 服务端具体的类型为 NioServerSocketChannel,具体 NioServerSocketChannel 创建流程请查看 https://www.cnblogs.com/programmlover/p/14826788.html
  2. STEP2:调用 init 方法初始化 channel
  3. 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 一个新的连接时都会使用这些属性进行配置

posted @ 2019-11-24 20:58  programmLover  阅读(356)  评论(0)    收藏  举报