NOTE

1. Creating the Server

bind, channelFactory, and creation of NioServerSocketChannel

JavaCreated Updated 1 min readhistorical

This is a historical learning note and may contain outdated or incomplete understanding.

bind

Start from this line and trace bind:

ChannelFuture future = bootstrap.bind(8000).sync();

Eventually execution reaches io.netty.bootstrap.AbstractBootstrap#doBind:

private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();// this line
        final Channel channel = regFuture.channel();
        .....
}
  • initAndRegister
final ChannelFuture initAndRegister() {
    Channel channel = null;
    //..
        // Call channelFactory.newChannel to create the channel.
        // We need to determine which channelFactory this is.
        channel = channelFactory.newChannel();
        init(channel);

    //...

    return regFuture;
}

channel

To determine which channelFactory is used, go back to this code:

ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup)
        .channel(NioServerSocketChannel.class)// key point
  • io.netty.bootstrap.AbstractBootstrap#channel
public B channel(Class<? extends C> channelClass) {
    if (channelClass == null) {
        throw new NullPointerException("channelClass");
    }
    // This method assigns channelFactory to ReflectiveChannelFactory.
    return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}

From the code above, we know that the factory used by channelFactory.newChannel() is ReflectiveChannelFactory, and the server-startup channelClass is NioServerSocketChannel.class.

First look at its newChannel method.

  • io.netty.channel.ReflectiveChannelFactory#newChannel
 public T newChannel() {
    try {
        // Use reflection to invoke the no-argument constructor,
        // which is NioServerSocketChannel here.
        return clazz.getConstructor().newInstance();
    } catch (Throwable t) {
        throw new ChannelException("Unable to create Channel from class " + clazz, t);
    }
}

Create NioServerSocketChannel

  • Constructor
public NioServerSocketChannel() {
    // newSocket uses the JDK provider.openServerSocketChannel() underneath.
    // Then it calls the parameterized constructor.
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}

 public NioServerSocketChannel(ServerSocketChannel channel) {
    // Call the AbstractNioMessageChannel parent constructor.
    // AbstractNioMessageChannel then calls the AbstractNioChannel parent constructor.
    super(null, channel, SelectionKey.OP_ACCEPT);
    // Configuration class used to configure options and other settings.
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
  • AbstractNioChannel
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    // Call AbstractChannel.
    // Both clients and servers implement it.
    super(parent);
    this.ch = ch;
    this.readInterestOp = readInterestOp;
    try {
        ch.configureBlocking(false);// configure NIO as non-blocking
    } catch (IOException e) {
        try {
            ch.close();
        } catch (IOException e2) {
            if (logger.isWarnEnabled()) {
                logger.warn(
                        "Failed to close a partially initialized socket.", e2);
            }
        }

        throw new ChannelException("Failed to enter non-blocking mode.", e);
    }
}
  • AbstractChannel
protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();// channelId
    unsafe = newUnsafe();// Unsafe class used to interact with low-level JDK NIO APIs
    pipeline = newChannelPipeline();// create the pipeline
}

Discussion

Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub