Netty source code analysis of the four series: Netty start of NioServerSocketChannel create

introduction

Last article mainly Nettystart-up process, involving the NioEventLoopGrouprelevant details are described in detail, this article introduces a number of other startup initialization steps.

  • ChannelCreation and initialization process
  • to sum up

First, the Channelcreation and initialization process

ChannelIs Nettyfor the network abstraction layer is implemented, it may correspond to JDKthe NIOimplementation of the package, Nettythe service-side Channeltype NioServerSocketChannel. To analyze the following NioServerSocketChannelcreated and initialized.

1, Port Binding

During startup operation is an important port binding, and NioServerSocketChannelthe creation is carried out in this process. ServerBootStrapThe bind()method

ChannelFuture f = b.bind(PORT).sync();

View the corresponding source code, the actual call is AbstractBootstrapclass bindmethod:

...
 public ChannelFuture bind(int inetPort) {
        return bind(new InetSocketAddress(inetPort));
    }
...

 public ChannelFuture bind(SocketAddress localAddress) {
        validate();
        return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
    }
...
 private ChannelFuture doBind(final SocketAddress localAddress) {
 		//初始化channel
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }
		//若注册成功,则进行bind操作
        if (regFuture.isDone()) {
            // At this point we know that the registration was complete and successful.
            ChannelPromise promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
            // 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;
        }
    }

2. CreateNioServerSocketChannel

initAndRegister()Completed NioServerSocketChannelinitialization and registration of the operation, after initialization and registration is complete, the actual binding operation, we continue to look down:

final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
        	//channel工厂创建新的channel
            channel = channelFactory.newChannel();
            //初始化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);
        }
		//注册channel
        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;
    }

Creating channelthe actual call is ReflectiveChannelFactoryin the newChannelmethod.

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {

	private final Constructor<? extends T> constructor;

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
                    " does not have a public non-arg constructor", e);
        }
    }
    
  	@Override
    public T newChannel() {
        try {
            return constructor.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
        }
    }
...
}

From the above we can see the code, clazz.getConstructor().newInstance()created by way of reflection Channel.

ChannelOnce you've created, perform Channelthe initialization operation,

 @Override
    void init(Channel channel) {
    	//设置channle选项
        setChannelOptions(channel, options0().entrySet().toArray(newOptionArray(0)), logger);
        //设置channel属性
        setAttributes(channel, attrs0().entrySet().toArray(newAttrArray(0)));

        ChannelPipeline p = channel.pipeline();

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions =
                childOptions.entrySet().toArray(newOptionArray(0));
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));

        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }

                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

Second, summary

This paper describes NioServerSocketChannelthe process of creating and source code analysis, explained later in the article continue to operate after the channel is created, such as waiting for a connection, and so on.

发布了88 篇原创文章 · 获赞 49 · 访问量 10万+

Guess you like

Origin blog.csdn.net/Diamond_Tao/article/details/104132472