After a rough introduction to Netty in the last article, this article will cover the startup process of netty’s server in detail.

ServerBootstrap

For those of you who have seen the previous example, ServerBootstrap plays an important role in Netty server startup. AbstractBootstrap is a server-side bootstrap class provided by Netty, derived from AbstractBootstrap. ServerBootstrap consists of two parts: bossGroup and workerGroup. BossGroup is used to bind ports and receive requests from clients. After receiving requests, bossGroup sends these requests to workGroup for processing. Just like the boss and employee in real life, they set up their own company (binding port), go outside to receive work (receiving requests), and ask employees to do work (letting workers handle it).

Port binding

Before port binding, check whether the bossGroup and workerGroup of the bootstrap class (ServerBootstrap) are set and then call doBind.

    private ChannelFuture doBind(final SocketAddress localAddress) {
        // Initialize and register a channel and return chanelFuture
        final ChannelFuture regFuture = initAndRegister();
        // Get the actual channel (initialization and registration may not be complete)
        final Channel channel = regFuture.channel();
        // If an exception occurs, return directly
        if(regFuture.cause() ! =null) {
            return regFuture;
        }
        // When the chanel related processing has been completed
        if (regFuture.isDone()) {
            // The channel is registered successfully
            ChannelPromise promise = channel.newPromise();
            // Perform related binding operations
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
            // Registration is usually completed at this point, just in case
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            // Add a listener
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if(cause ! =null) {
                        promise.setFailure(cause);
                    } else {
                        / / modify registration status to success (when registration is not in the use of global executor, use the channel their, see https://github.com/netty/netty/issues/2586).
                        promise.registered();
                        // Perform related binding operationsdoBind0(regFuture, channel, localAddress, promise); }}});returnpromise; }}Copy the code

The above code has two main parts: initializing and registering a channel and binding port.

Initialize and register a channel

    final ChannelFuture initAndRegister() { Channel channel = null; Try {/ / production of the new channel channel. = channelFactory newChannel (); // Initialize channel init(channel); } catch (Throwable t) {if(channel ! // Forcibly close channel.unsafe(). CloseForcibly (); // Force GlobalEventExecutor because channel is not registered yetreturn new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
            }
            returnnew DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t); } // Register channel ChannelFuture regFuture = config().group().register(channel);if(regFuture.cause() ! = null) {if (channel.isRegistered()) {
                channel.close();
            } else{ channel.unsafe().closeForcibly(); }}return regFuture;
    }
Copy the code

Channel initialization:

Void init(Channel Channel) throws Exception {// Obtain the optional Map of bossChannel final Map<ChannelOption<? >, Object> options = options0(); synchronized (options) {setChannelOptions(channel, options, logger); } // Obtain bossChannel's attribute Map final Map<AttributeKey<? >, Object> attrs = attrs0(); synchronized (attrs) {for(Entry<AttributeKey<? >, Object> e : attrs.entrySet()) { @SuppressWarnings("unchecked") AttributeKey<Object> key = (AttributeKey<Object>) e.getKey(); channel.attr(key).set(e.getValue()); } } ChannelPipeline p = channel.pipeline(); Final EventLoopGroup currentChildGroup = childGroup; final ChannelHandler currentChildHandler = childHandler; final Entry<ChannelOption<? >, Object>[] currentChildOptions; final Entry<AttributeKey<? >, Object>[] currentChildAttrs; synchronized (childOptions) { currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size())); } synchronized (childAttrs) { currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size())); } p.addLast(new ChannelInitializer<Channel>() { @Override public void initChannel(final Channel ch) throws Exception { final ChannelPipeline pipeline = ch.pipeline(); // Add handler to pipeline ChannelHandler handler = config.handler();if(handler ! = null) { pipeline.addLast(handler); } // Add ServerBootstrapAcceptor to the pipeline via EventLoop, ensuring that it is the last handler ch.eventLoop().execute(new)Runnable() {
                    @Override
                    public void run() { pipeline.addLast(new ServerBootstrapAcceptor( ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)); }}); }}); }Copy the code

The registration method of a channel is finally called doRegister. Different channels have different methods. Nio is used as an example below:

    protected void doRegister() throws Exception {
        boolean selected = false;
        for(; ;) SelectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);return;
            } catch (CancelledKeyException e) {
                if(! selected) { eventLoop().selectNow(); selected =true;
                } else{ throw e; }}}}Copy the code

Binding port

The final call is the doBind method of NioServerSocketChannel.

    protected void doBind(SocketAddress localAddress) throws Exception {
        if (PlatformDependent.javaVersion() >= 7) {
            javaChannel().bind(localAddress, config.getBacklog());
        } else {
            javaChannel().socket().bind(localAddress, config.getBacklog()); }}Copy the code

This completes the entire startup process of the Netty server.

The code comments for the post are all at github.com/KAMIJYOUDOU… , interested in children’s shoes can pay attention to.


This is the end of this article, if you feel that there is a harvest after reading, welcome to like, follow, add the public account [level 2 natural disaster], see more wonderful history!!