netty源码阅读之服务器启动之服务端channel的创建

本文详细解析了Netty中服务端Channel的创建过程,包括通过反射创建NioServerSocketChannel,配置TCP参数,设置非阻塞模式等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先是我们一段用户的代码 

    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")
                    .handler(new ServerHandler())
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new AuthHandler());
                            //..

                        }
                    });

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

            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

我们分以下步骤分析源码:

1、通过什么方式创建服务端channel。

2、 创建服务端channel的时候做了什么事情。

 

通过什么方式创建服务端channel

1、bind()用户代码入口

2、initAndRegister()初始化并注册

3、newChannel()创建服务端channel

从bind方法进入:层层深入,到了doBind方法,里面有一个initAndRegister()方法(在AbstractBootstrap类里面):

    final ChannelFuture initAndRegister() {
        Channel channel = null;

        try {
            channel = this.channelFactory.newChannel();
            this.init(channel);
        } catch (Throwable var3) {
            if(channel != null) {
                channel.unsafe().closeForcibly();
            }

            return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
        }

        ...
    }

也就是有一个channelFactory类工厂,产生我们的Channel。具体这个channelFactory的实现是什么?我们目前先猜测是ReflectiveChannelFactory,进入ReflectiveChannelFactory的newChannel()方法,明显是使用反射的实现:

    public T newChannel() {
        try {
            return (Channel)this.clazz.newInstance();
        } catch (Throwable var2) {
            throw new ChannelException("Unable to create Channel from class " + this.clazz, var2);
        }
    }

那么这个clazz是什么?带着这两个疑问,来到用户代码的这一行:

 .channel(NioServerSocketChannel.class)

这一行好像和clazz有关。进入bind方法:

    public B channel(Class<? extends C> channelClass) {
        if(channelClass == null) {
            throw new NullPointerException("channelClass");
        } else {
            return this.channelFactory((io.netty.channel.ChannelFactory)(new ReflectiveChannelFactory(channelClass)));
        }
    }

看channelFactory方法,一直点进去,就是把传入的ReflectiveChannelFactory传递给AbstractBootstrap类,作为他的其中一个成员变量,这里就解释了前面的channelFactory的实现是什么,就是ReflectiveChannelFactory。

那么我们进入new ReflectiveChannelFactory(channelClass)看看它做了什么:

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        if(clazz == null) {
            throw new NullPointerException("clazz");
        } else {
            this.clazz = clazz;
        }
    }

很明显,刚刚的clazz就是我们用户传进去的NioServerSocketChannel.class

这里,创建服务端channel也就是NioServerSocketChannel的代码已经清晰了,通过反射去创建NioServerSocketChannel。

 

创建服务端channel的时候做了什么事情

1、newSocket()[通过jdk来创建底层jdk channel]

2、NioServerSocketChannelConfig()[tcp参数类配置]

3、AbstractNioChannel

       A、configureBlocking(false)[阻塞模式]

       B、AbstractChannel()[创建id,unsafe,pipeline]

我们点进去NioServerSocketChannel这个类,看它的构造方法,也就是在构造的时候做了什么事情:

无参构造器:

    public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }
DEFAULT_SELECTOR_PROVIDER的来源:
 private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
newSocket的来源:
    private static java.nio.channels.ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
            return provider.openServerSocketChannel();
        } catch (IOException var2) {
            throw new ChannelException("Failed to open a server socket.", var2);
        }
    }

这些其实都是使用jdk底层构造ServerSocketChannel的方法创建的。

接下去看无参构造器调用一个参数的构造器:

    public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) {
        super((Channel)null, channel, 16);
        this.config = new NioServerSocketChannel.NioServerSocketChannelConfig(this, this.javaChannel().socket());
    }

这里主要做了两件事情:

1、调用父类的构造器

2、初始化一个NioServerSocketChannelConfig,以后可以使用这个tcp参数设置类。

第二点可以不用解释了,第一点层层进入,到了AbstractNioChannel(这个AbstractNioChannel是服务端和客户端channel的基类,一些公共的东西都在这个类里面创建)的这个构造方法:

    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        this.readInterestOp = readInterestOp;
        try {
            ch.configureBlocking(false);
        } 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);
        }
    }

首先把ch传入,然后把readInterestOp也传入,然后是一个nio编程很常用的设置,设置为非阻塞模式:

ch.configureBlocking(false);

最后我们查看第一行super(parent);

    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        unsafe = newUnsafe();
        pipeline = newChannelPipeline();
    }

这个AbstractChannel是客户端和服务端共用的基类,他们都会创建id,unsafe和pipeline(其中unsafe和tcp底层读写有关)

这段代码就是为这个服务端channel添加一个id,一个unsafe、一个pipeline。

 

自此,我们创建服务端channel的源码已经分析完,记住这些东西,以后会串起来。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值