美文网首页大数据深入浅出Netty源码剖析程序员
netty源码走读(服务端Channel创建流程)

netty源码走读(服务端Channel创建流程)

作者: gfgao | 来源:发表于2019-01-30 16:37 被阅读1次

    概念:

    NioEventLoop

    Channel:

    ByteBuf:

    PipeLine:

    ChannelHandler:

    服务器端启动流程:

    创建服务器端`Channel`->初始化服务器端`Channel`->注册`Selector`->端口绑定
    

    创建服务器端Channel从用户代码的bind()方法入口,调用initAndRegister()方法,在initAndRegister()方法中,调用newChannel()方法,创建服务器端Channel.
    ChannelFuture future = bootstrap.bind(8090).sync();

    调用流程

    整个调用过程逻辑相对比较清晰。

        final ChannelFuture initAndRegister() {
            Channel channel = null;
            try {
                channel = channelFactory.newChannel();
                init(channel);
            } catch (Throwable t) {
    

    我们跟进newChannel()方法,看一下Channel的创建过程.

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

    Channel的创建是以反射的方式创建。那我们就看一下clazz对应的实例是谁,从而也就知道了反射后创建的Channel的具体类型了。

    public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
    
        private final Class<? extends T> clazz;
    
        public ReflectiveChannelFactory(Class<? extends T> clazz) {
            if (clazz == null) {
                throw new NullPointerException("clazz");
            }
            this.clazz = clazz;
        }
    

    clazz是从外部接收的一个Class实例。既然是外部接收的,就看一下我们的Server端代码

    bootstrap.group(master,worker)
                    .channel(NioServerSocketChannel.class)
    

    我们跟进channel()方法

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

    我们传进去的channelClass也就是NioServerSocketChannel.class,交给了ReflectiveChannelFactory。这样就知道了我们服务端创建的是NioServerSocketChannel。我们跟进NioServerSocketChannel类,看一下这个类的实例化过程。

    由于在利用反射创建NioServerSocketChannel时候,channel = channelFactory.newChannel();没有传参进去,我们需要跟进NioServerSocketChannel的无参构造函数。

        public NioServerSocketChannel() {
            this(newSocket(DEFAULT_SELECTOR_PROVIDER));
        }
    

    跟进this构造函数

        public NioServerSocketChannel(ServerSocketChannel channel) {
            super(null, channel, SelectionKey.OP_ACCEPT);
            config = new NioServerSocketChannelConfig(this, javaChannel().socket());
        }
    

    抽丝剥茧,跟进newSocket()方法,并将newSocket的返回值ServerSocketChannel作为参数传递给NioServerSocketChannel(ServerSocketChannel channel)

        private static ServerSocketChannel newSocket(SelectorProvider provider) {
            try {
                /**
                 *  Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in
                 *  {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.
                 *
                 *  See <a href="https://github.com/netty/netty/issues/2308">#2308</a>.
                 */
                return provider.openServerSocketChannel();
            } catch (IOException e) {
                throw new ChannelException(
                        "Failed to open a server socket.", e);
            }
        }
    

    newSocket中,nettyjdk底层Socket建立了连接。

    在初始化NioServerSocketChannel时,创建了NioServerSocketChannelConfig,主要负责给创建的jdk底层的Socket的TCP相关配置。

    我们跟进

    public NioServerSocketChannel(ServerSocketChannel channel) {
            super(null, channel, SelectionKey.OP_ACCEPT);
    

    进入父类的构造函数

        protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
            super(parent, ch, readInterestOp);
        }
    

    继续跟进

        protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
            super(parent);
            this.ch = ch;
            this.readInterestOp = readInterestOp;
            try {
                ch.configureBlocking(false);
            } catch (IOException e) {
    

    当我们看到ch.configureBlocking(false)这行代码的时候,就知道了创建出来的Socket是非阻塞模式。

    继续跟进父类

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

    创建了Channel的唯一标识id,unsafe封装了Channel和底层相关的操作,pipeline封装了跟服务端程序相关的逻辑链。至此服务端NioServerSocketChannel创建成功。

    相关文章

      网友评论

        本文标题:netty源码走读(服务端Channel创建流程)

        本文链接:https://www.haomeiwen.com/subject/qbscsqtx.html