netty源码解析二之启动ServerBootstrap

二:启动ServerBootstrap

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ServerBootstrap主要负责对主从Reactor线程组相关的配置进行管理,其中带child前缀的配置方法是对从Reactor线程组的相关配置管理。从Reactor线程组中的Sub Reactor负责管理的客户端NioSocketChannel相关配置存储在ServerBootstrap结构中。

父类AbstractBootstrap则是主要负责对主Reactor线程组相关的配置进行管理,以及主Reactor线程组中的Main Reactor负责处理的服务端ServerSocketChannel相关的配置管理。

1. 配置主从Reactor线程组

//(2) 创建ServerBootstrap,以引导和绑定服务器
ServerBootstrap b = new ServerBootstrap();
//设置反应堆线程组,boss用于处理连接监听事件,worker用于处理传输数据事件
b.group(boosGroup,workerGroup)
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
public B group(EventLoopGroup group) {
    ObjectUtil.checkNotNull(group, "group");
    if (this.group != null) {
        throw new IllegalStateException("group set already");
    }
    this.group = group;
    return self();
}
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
    private volatile EventLoopGroup childGroup;//Sub Reactor线程组
        public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);//设置工作线程组和boss组
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = ObjectUtil.checkNotNull(childGroup, "childGroup");
        return this;
    }
    }

2.配置服务端channel

EventLoopGroup workerGroup = new NioEventLoopGroup();
b.channel(NioServerSocketChannel.class)//(3) 指定所使用的 NIO 传输 Channel
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {

    public B channel(Class<? extends C> channelClass) {
        return channelFactory(new ReflectiveChannelFactory<C>(
                ObjectUtil.checkNotNull(channelClass, "channelClass")
        ));
    }
    
        public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
        return channelFactory((ChannelFactory<C>) channelFactory);
    }
    
        public B channelFactory(ChannelFactory<? extends C> channelFactory) {
        ObjectUtil.checkNotNull(channelFactory, "channelFactory");
        if (this.channelFactory != null) {
            throw new IllegalStateException("channelFactory set already");
        }
        //封装channel
        this.channelFactory = channelFactory;
        return self();
    }
}

这里就是将channel类封装成反射工厂对象,可通过ReflectiveChannelFactory创建channel对象。在Netty服务端启动的过程中,会通过这个ChannelFactory去创建相应的Channel实例。

下面为ServerSocketChannel在不同IO模型下的实现:

BIONIOAIO
OioServerSocketChannelNioServerSocketChannelAioServerSocketChannel

EventLoopGroupReactor线程组在不同IO模型下的实现:

BIONIOAIO
ThreadPerChannelEventLoopGroupNioEventLoopGroupAioEventLoopGroup

2.1 ReflectiveChannelFactory

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 { //获取Channel构造
            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);
        }
    }

    @Override
    public String toString() {
        return StringUtil.simpleClassName(ReflectiveChannelFactory.class) +
                '(' + StringUtil.simpleClassName(constructor.getDeclaringClass()) + ".class)";
    }
}

可以看出该类通过泛型T加反射创建对象的,泛型T继承channel,表示通过工厂反射创建channel类型。

3.为NioServerSocketChannel配置端口

ServerBootstrap b = new ServerBootstrap();
//(4) 使用指定的端口设置套接字地址
b.localAddress(new InetSocketAddress(port))

4.为NioServerSocketChannel配置ChannelOption

ServerBootstrap b = new ServerBootstrap();
//是否开启TCP底层心跳机制,默认2小时,默认关闭
                    b.option(ChannelOption.SO_KEEPALIVE,true)
                    //设置buf分配器,默认池化buf分配器
                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    //true:立即发送数据(默认true). false:将小的碎片数据连接成更大的报文来最小化所发送报文的数量(相当于开启Nagle算法)
                    .option(ChannelOption.TCP_NODELAY, true)
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
    private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>(); //serverSocket配置
    
        public <T> B option(ChannelOption<T> option, T value) {
        ObjectUtil.checkNotNull(option, "option");
        synchronized (options) {
            if (value == null) {
                options.remove(option);
            } else {
                options.put(option, value);
            }
        }
        return self();
    }
    }

这里将所有option存储map中。

由于客户端NioSocketChannel是由从Reactor线程组中的Sub Reactor来负责处理,所以涉及到客户端NioSocketChannel所有的方法和配置全部是以child前缀开头。

ServerBootstrap b = new ServerBootstrap();
//为客户端channel设置选项
b.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
    private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();//子channel配置
        public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
        ObjectUtil.checkNotNull(childOption, "childOption");
        synchronized (childOptions) {
            if (value == null) {
                childOptions.remove(childOption);
            } else {
                childOptions.put(childOption, value);
            }
        }
        return this;
    }
    }

子channel也是存储在map中。

5. 为服务端NioServerSocketChannel中的Pipeline配置ChannelHandler

ServerBootstrap b = new ServerBootstrap();
b.handler(new ChannelHandler() {
                        @Override
                        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
                            System.out.println("add");
                        }

                        @Override
                        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
                            System.out.println("remove");
                        }

                        @Override
                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                            System.out.println("exception");
                        }
                    })
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
    //父channelhandler
    private volatile ChannelHandler handler;
    public B handler(ChannelHandler handler) {
        this.handler = ObjectUtil.checkNotNull(handler, "handler");
        return self();
    }
    
    }

NioServerSocketChannel中的Pipeline添加ChannelHandler分为两种方式:

  • 显示添加,如上所示。当需要添加多个handler时,可通过ChannelInitializer向pipe添加
  • 隐式添加,主reactor启动时会注册ServerBootstrapAcceptor,主要用于接收客户端请求后,初始化客户端NioSocketChannel,在从Reactor线程组中选取一个Sub Reactor,通过此handler创建NioSocketChannel,将客户端NioSocketChannel 注册到Sub Reactor中的selector上。

6. 为客户端NioSocketChannel中的Pipeline配置ChannelHandler

 ServerBootstrap b = new ServerBootstrap();
//(5) 添加一个EchoServerHandler到于Channel的 ChannelPipeline  ,配置子通道channel,也就是accept的channel
                    b.childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            //EchoServerHandler 被标注为@Shareable,所以我们可以总是使用同样的实例
                            //这里对于所有的客户端连接来说,都会使用同一个 EchoServerHandler,因为其被标注为@Sharable
                            //ChannelInitializer执行完initChannel,会将自己删除,因为一条通道只需要初始化一次

                            /**
                             * 那为什么不直接添加ChannelHandler而是选择用ChannelInitializer呢?
                             * 这里主要有两点原因:
                             * 前边我们提到,客户端NioSocketChannel是在服务端accept连接后,在服务端NioServerSocketChannel中被创建出来的。但是此时我们正处于配置ServerBootStrap阶段,服务端还没有启动,更没有客户端连接上来,此时客户端NioSocketChannel还没有被创建出来,所以也就没办法向客户端NioSocketChannel的pipeline中添加ChannelHandler。
                             * 客户端NioSocketChannel中Pipeline里可以添加任意多个ChannelHandler,但是Netty框架无法预知用户到底需要添加多少个ChannelHandler,所以Netty框架提供了回调函数ChannelInitializer#initChannel,使用户可以自定义ChannelHandler的添加行为。
                             * 当客户端NioSocketChannel注册到对应的Sub Reactor上后,紧接着就会初始化NioSocketChannel中的Pipeline,此时Netty框架会回调ChannelInitializer#initChannel执行用户自定义的添加逻辑。
                             */
                            ch.pipeline().addLast(echoChannelHandler);
                            ch.pipeline().addLast(serverHandler);//使用一个EchoServerHandler 的实例初始化每一个新的Channel
                        }
                    });

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

那为什么不直接添加ChannelHandler而是选择用ChannelInitializer呢?

这里主要有两点原因:

  • 前边我们提到,客户端NioSocketChannel是在服务端accept连接后,在服务端NioServerSocketChannel中被创建出来的。但是此时我们正处于配置ServerBootStrap阶段,服务端还没有启动,更没有客户端连接上来,此时客户端NioSocketChannel还没有被创建出来,所以也就没办法向客户端NioSocketChannel的pipeline中添加ChannelHandler
  • 客户端NioSocketChannelPipeline里可以添加任意多个ChannelHandler,但是Netty框架无法预知用户到底需要添加多少个ChannelHandler,所以Netty框架提供了回调函数ChannelInitializer#initChannel,使用户可以自定义ChannelHandler的添加行为。

当客户端NioSocketChannel注册到对应的Sub Reactor上后,紧接着就会初始化NioSocketChannel中的Pipeline,此时Netty框架会回调ChannelInitializer#initChannel执行用户自定义的添加逻辑。

通道注册完成后,会调用fireChannelRegistered,触发通道注册事件

@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {

@Override
@SuppressWarnings("unchecked")
public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    // Normally this method will never be called as handlerAdded(...) should call initChannel(...) and remove
    // the handler.
    //将channel添加到pipe
    if (initChannel(ctx)) {
        // we called initChannel(...) so we need to call now pipeline.fireChannelRegistered() to ensure we not
        // miss an event.
        ctx.pipeline().fireChannelRegistered();

        // We are done with init the Channel, removing all the state for the Channel now.
        removeState(ctx);
    } else {
        // Called initChannel(...) before which is the expected behavior, so just forward the event.
        ctx.fireChannelRegistered();
    }
}

    @SuppressWarnings("unchecked")
    private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
        if (initMap.add(ctx)) { // Guard against re-entrance.
            try {
                //执行初始化handler方法,将父handler添加到pipe,以及ServerBootstrapAcceptor
                initChannel((C) ctx.channel());
            } catch (Throwable cause) {
                // Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
                // We do so to prevent multiple calls to initChannel(...).
                exceptionCaught(ctx, cause);
            } finally {
                ChannelPipeline pipeline = ctx.pipeline();
                if (pipeline.context(this) != null) {
                    //如果包含当前handler,则删除当前handler
                    pipeline.remove(this);
                }
            }
            return true;
        }
        return false;
    }

    protected abstract void initChannel(C ch) throws Exception;
}

这里调用的initChannel抽象方法就是我们实现的方法。

//(5) 添加一个EchoServerHandler到于Channel的 ChannelPipeline  ,配置子通道channel,也就是accept的channel
.childHandler(new ChannelInitializer<SocketChannel>() {
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
        //EchoServerHandler 被标注为@Shareable,所以我们可以总是使用同样的实例
        //这里对于所有的客户端连接来说,都会使用同一个 EchoServerHandler,因为其被标注为@Sharable
        //ChannelInitializer执行完initChannel,会将自己删除,因为一条通道只需要初始化一次

        /**
         * 那为什么不直接添加ChannelHandler而是选择用ChannelInitializer呢?
         * 这里主要有两点原因:
         * 前边我们提到,客户端NioSocketChannel是在服务端accept连接后,在服务端NioServerSocketChannel中被创建出来的。但是此时我们正处于配置ServerBootStrap阶段,
         * 服务端还没有启动,更没有客户端连接上来,此时客户端NioSocketChannel还没有被创建出来,所以也就没办法向客户端NioSocketChannel的pipeline中添加ChannelHandler。
         * 客户端NioSocketChannel中Pipeline里可以添加任意多个ChannelHandler,但是Netty框架无法预知用户到底需要添加多少个ChannelHandler,
         * 所以Netty框架提供了回调函数ChannelInitializer#initChannel,使用户可以自定义ChannelHandler的添加行为。
         * 当客户端NioSocketChannel注册到对应的Sub Reactor上后,紧接着就会初始化NioSocketChannel中的Pipeline,
         * 此时Netty框架会回调ChannelInitializer#initChannel执行用户自定义的添加逻辑。
         */
        ch.pipeline().addLast(echoChannelHandler);
        ch.pipeline().addLast(serverHandler);//使用一个EchoServerHandler 的实例初始化每一个新的Channel
    }
});

7.Netty服务端的启动

ChannelFuture f = b.bind().sync();
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
  
      public ChannelFuture bind() {
        //校验netty核心组件是否配置齐全
        validate();
        SocketAddress localAddress = this.localAddress;
        if (localAddress == null) {
            throw new IllegalStateException("localAddress not set");
        }
        //启动服务端,绑定端口地址,接收客户端连接
        return doBind(localAddress);
    }
  
  private ChannelFuture doBind(final SocketAddress localAddress) {
        //1.异步创建,初始化,注册ServerSocketChannel到main reactor上
        //创建通道并注册到eventLoop,初始化pipline,并添加handler到piple,打开一个nio的ServerSocketChannel,并设置非阻塞。
        //将channel注册到eventLoop的selector上,将父handler注册到pipe,以及剔除初始化的handler
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }

        //2.任务完成则绑定端口
        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);
            //3.如果此时注册操作没有完成,则向regFuture添加operationComplete回调函数,注册成功后回调。
            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();
                        //socket绑定地址
                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
    }
  
}

initAndRegister

final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        //1.创建通道,打开一个nio的ServerSocketChannel,设置accept事件并设置非阻塞。初始化pipline。
        channel = channelFactory.newChannel();
        //2.初始化channel,设置Attributes和option
        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);
    }
    //3.向MainReactor注册ServerSocketChannel,
    // 将channel注册到eventLoop的selector上,事件默认0,将accept和父handler注册到pipe,以及剔除初始化的handler
    // 获取的是bossGroup进行注册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;
}

该函数主要创建NioServerSocketChannel,并对此初始化,然后注册到Main Reactor中。

1.1 创建通道
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
    @Override
    public T newChannel() {
        try {
            return constructor.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
        }
    }
    }

简单通过反射创建

//一个 io.netty.channel.socket.ServerSocketChannel 实现,它使用基于 NIO 选择器的实现来接受新连接。
public class NioServerSocketChannel extends AbstractNioMessageChannel
                             implements io.netty.channel.socket.ServerSocketChannel {
  //SelectorProvider(用于创建Selector和Selectable Channels)
      private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
      //ServerSocketChannel相关的配置
    private final ServerSocketChannelConfig config;
  
     public NioServerSocketChannel() {
        //打开一个nio的ServerSocketChannel,并设置非阻塞,以及标记accept事件。
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }
  
      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);
        }
    }
  
      public NioServerSocketChannel(ServerSocketChannel channel) {
        //设置非阻塞
        super(null, channel, SelectionKey.OP_ACCEPT);
        //相当于把本类和ServerSocketChannel存储配置中
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }
  
}

这里创建了一个ServerSocketChannel,并注册OP_ACCEPT事件,创建channel的配置类,该类封装了当前对象和nio原生socket。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AbstractNioMessageChannel:对NioServerSocketChannel底层读写行为的封装和定义

AbstractNioChannel

public abstract class AbstractNioChannel extends AbstractChannel {
    //JDK NIO原生Selectable Channel
    private final SelectableChannel ch;
        // Channel监听事件集合 这里是SelectionKey.OP_ACCEPT事件
    protected final int readInterestOp;
    
    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) {
                logger.warn(
                            "Failed to close a partially initialized socket.", e2);
            }

            throw new ChannelException("Failed to enter non-blocking mode.", e);
        }
    }
}

这里分别做了三件事

  • 封装JDK NIO原生ServerSocketChannel
  • 封装channel感兴趣的事件,这里为OP_ACCEPT
  • 设置非阻塞,用于多路复用。

AbstractChannel

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
      //channel是由创建层次的,比如ServerSocketChannel 是 SocketChannel的 parent
    private final Channel parent;
      //channel全局唯一ID machineId+processId+sequence+timestamp+random
    private final ChannelId id;
      //unsafe用于封装对底层socket的相关操作
    private final Unsafe unsafe;
      //为channel分配独立的pipeline用于IO事件编排
    private final DefaultChannelPipeline pipeline;
  
      protected AbstractChannel(Channel parent) {
        //定义父通道,对于NioServerSocketChannel来说parent为null,NioSocketChannel为接收到该连接的服务器连接监听通道
        this.parent = parent;
        //channel全局唯一ID machineId+processId+sequence+timestamp+random
        id = newId();
        //底层nio通道,完成实际io操作
        unsafe = newUnsafe();
        //一条通道拥有一条流水线,将channel存储pipline
        pipeline = newChannelPipeline();
    }
  
      protected ChannelId newId() {
        return DefaultChannelId.newInstance();
    }
  
}
  • parent保存上一级channel,channel是由创建层次的,比如ServerSocketChannel 是 SocketChannel的 parent
  • 为channel分配全局唯一ID,ChannelId由机器Id(machineId),进程Id(processId),序列号(sequence),时间戳(timestamp),随机数(random)构成
public final class DefaultChannelId implements ChannelId {
    public static DefaultChannelId newInstance() {
        return new DefaultChannelId();
    }
    
        private DefaultChannelId() {
        data = new byte[MACHINE_ID.length + PROCESS_ID_LEN + SEQUENCE_LEN + TIMESTAMP_LEN + RANDOM_LEN];
        int i = 0;

        // machineId
        System.arraycopy(MACHINE_ID, 0, data, i, MACHINE_ID.length);
        i += MACHINE_ID.length;

        // processId
        i = writeInt(i, PROCESS_ID);

        // sequence
        i = writeInt(i, nextSequence.getAndIncrement());

        // timestamp (kind of)
        i = writeLong(i, Long.reverse(System.nanoTime()) ^ System.currentTimeMillis());

        // random
        int random = PlatformDependent.threadLocalRandom().nextInt();
        i = writeInt(i, random);
        assert i == data.length;

        hashCode = Arrays.hashCode(data);
    }
}
  • 创建NioServerSocketChannel的底层操作类,这里为io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafeUnsafeChannel接口的一个内部接口,用于定义实现对Channel底层的各种操作,Unsafe接口定义的操作行为只能由Netty框架的Reactor线程调用,用户线程禁止调用。
interface Unsafe {
        
        //分配接收数据用的Buffer
        RecvByteBufAllocator.Handle recvBufAllocHandle();

        //服务端绑定的端口地址
        SocketAddress localAddress();
        //远端地址
        SocketAddress remoteAddress();
        //channel向Reactor注册
        void register(EventLoop eventLoop, ChannelPromise promise);

        //服务端绑定端口地址
        void bind(SocketAddress localAddress, ChannelPromise promise);
        //客户端连接服务端
        void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
        //关闭channle
        void close(ChannelPromise promise);
        //读数据
        void beginRead();
        //写数据
        void write(Object msg, ChannelPromise promise);

    }
  • 创建pipeline,主要用于编排handler。本质是个双向队列

    public class DefaultChannelPipeline implements ChannelPipeline {
          //pipeline中的头结点
        final AbstractChannelHandlerContext head;
        //pipeline中的尾结点
        final AbstractChannelHandlerContext tail;
      
          protected DefaultChannelPipeline(Channel channel) {
            //pipeline中持有对应channel的引用
            this.channel = ObjectUtil.checkNotNull(channel, "channel");
            succeededFuture = new SucceededChannelFuture(channel, null);
            voidPromise =  new VoidChannelPromise(channel, true);
    
            tail = new TailContext(this);
            head = new HeadContext(this);
    
            head.next = tail;
            tail.prev = head;
        }
    }
    

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

到此为止NioServerSocketChannel内容如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.2 初始化NioServerSocketChannel
 @Override
    void init(Channel channel) {
        //1.向NioServerSocketChannelConfig设置ServerSocketChannelOption
        setChannelOptions(channel, newOptionsArray(), logger);
        //2.向netty自定义的NioServerSocketChannel设置attributes
        setAttributes(channel, newAttributesArray());

        //获取pipe
        ChannelPipeline p = channel.pipeline();
        //获取从Reactor线程组
        final EventLoopGroup currentChildGroup = childGroup;
        //获取用于初始化客户端NioSocketChannel的ChannelInitializer
        final ChannelHandler currentChildHandler = childHandler;
        //获取用户配置的客户端SocketChannel的channelOption以及attributes
        final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);

        //3.向NioServerSocketChannel中的pipeline添加初始化ChannelHandler的逻辑
        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) {
                final ChannelPipeline pipeline = ch.pipeline();
                //获取父handler
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    //父handler添加到pipe
                    pipeline.addLast(handler);
                }

                //这里为什么不干脆直接将ChannelHandler添加到pipeline中,而是又使用到了ChannelInitializer呢?
                //其实原因有两点:
                //为了保证线程安全地初始化pipeline,所以初始化的动作需要由Reactor线程进行,而当前线程是用户程序的启动Main线程 并不是Reactor线程。这里不能立即初始化。
                //初始化Channel中pipeline的动作,需要等到Channel注册到对应的Reactor中才可以进行初始化,当前只是创建好了NioServerSocketChannel,但并未注册到Main Reactor上。
                //初始化NioServerSocketChannel中pipeline的时机是:当NioServerSocketChannel注册到Main Reactor之后,绑定端口地址之前。

                //在该初始化回调方法中,添加LoggingHandler是直接向pipeline中添加,而添加Acceptor为什么不是直接添加而是封装成异步任务呢?
                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {//管道添加ServerBootstrapAcceptor
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }
  • 向NioServerSocketChannelConfig设置ServerSocketChannelOption
  • 向netty自定义的NioServerSocketChannel设置attributes
    • 可以看到该channel继承AttributeMap,DefaultAttributeMap,正是它们定义了ChannelAttributes。用于向Channel添加用户自定义的一些信息。
    • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  • 获取从Reactor线程组childGroup,以及用于初始化客户端NioSocketChannelChannelInitializer,ChannelOption,ChannelAttributes,这些信息均是由用户在启动的时候向ServerBootstrap添加的客户端NioServerChannel配置信息。这里用这些信息来初始化ServerBootstrapAcceptor。因为后续会在ServerBootstrapAcceptor中接收客户端连接以及创建NioServerChannel
  • NioServerSocketChannel中的pipeline添加用于初始化pipelineChannelInitializer
这里为什么不干脆直接将ChannelHandler添加到pipeline中,而是又使用到了ChannelInitializer呢?
  • 为了保证线程安全地初始化pipeline,所以初始化的动作需要由Reactor线程进行,而当前线程是用户程序启动Main线程不是Reactor线程。这里不能立即初始化。
  • 初始化Channelpipeline的动作,需要等到Channel注册到对应的Reactor中才可以进行初始化,当前只是创建好了NioServerSocketChannel,但并未注册到Main Reactor上。

添加Acceptor为什么不是直接添加而是封装成异步任务呢?

此时NioServerSocketChannel中的pipeline结构如下图所示:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.3 向MainReactor注册ServerSocketChannel
ChannelFuture regFuture = config().group().register(channel);

ServerBootstrap获取主Reactor线程组NioEventLoopGroup,将NioServerSocketChannel注册到NioEventLoopGroup中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.3.1 主Reactor线程组中选取一个Main Reactor进行注册
public ChannelFuture register(Channel channel) {
    //简单的遍历EventLoop,然后将channel注册到eventLoop上
    return next().register(channel);
}

    @Override
    public EventLoop next() {
        //简单的遍历EventLoop
        return (EventLoop) super.next();
    }
@Override
public EventExecutor next() {
    return chooser.next();
}
private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;

    PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
        this.executors = executors;
    }

    @Override
    public EventExecutor next() {
        return executors[idx.getAndIncrement() & executors.length - 1];
    }
}

ReactorGroup中选取一个Reactor进行注册绑定。之后Channel生命周期内的所有IO 事件都由这个Reactor 负责处理,如 accept、connect、read、write等 IO 事件。

由于这里是NioServerSocketChannleMain Reactor进行注册绑定,所以Main Reactor主要负责处理的IO事件OP_ACCEPT事件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.3.2 向绑定后的Main Reactor进行注册

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
      @Override
    public ChannelFuture register(Channel channel) {
        //注册channel到绑定的Reactor上
        return register(new DefaultChannelPromise(channel, this));
    }
      @Override
    public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
        //将channel注册selector上,事件默认0,将accept和父handler注册到pipe,以及剔除初始化的handler
        promise.channel().unsafe().register(this, promise);
        return promise;
    }
  
}

通过NioServerSocketChannel中的Unsafe类执行底层具体的注册动作。

protected abstract class AbstractUnsafe implements Unsafe {
   @Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            ObjectUtil.checkNotNull(eventLoop, "eventLoop");
            //1.检查是否已经注册
            if (isRegistered()) {
                promise.setFailure(new IllegalStateException("registered to an event loop already"));
                return;
            }
            //2.EventLoop的类型要与Channel的类型一样  Nio Oio Aio
            if (!isCompatible(eventLoop)) {
                promise.setFailure(
                        new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
                return;
            }
            //3.在channel上设置绑定的Reactor
            AbstractChannel.this.eventLoop = eventLoop;

            /**
             * 执行channel注册的操作必须是Reactor线程来完成
             *
             * 1: 如果当前执行线程是Reactor线程,则直接执行register0进行注册
             * 2:如果当前执行线程是外部线程,则需要将register0注册操作 封装程异步Task 由Reactor线程执行
             * */
            if (eventLoop.inEventLoop()) {
                register0(promise);
            } else {
                try {
                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            //将channel注册selector上,事件默认0,将accept和父handler注册到pipe,以及剔除初始化的handler
                            register0(promise);
                        }
                    });
                } catch (Throwable t) {
                    logger.warn(
                            "Force-closing a channel whose registration task was not accepted by an event loop: {}",
                            AbstractChannel.this, t);
                    closeForcibly();
                    closeFuture.setClosed();
                    safeSetFailure(promise, t);
                }
            }
        }
  
}
  • 执行ChannelReactor注册的动作必须要确保是在Reactor线程中执行。

    • 如果当前线程是Reactor线程则直接执行注册动作register0
    • 如果当前线程不是Reactor线程,则需要将注册动作register0封装成异步任务,存放在Reactor中的taskQueue中,等待Reactor线程执行。

当前执行线程并不是Reactor线程,而是用户程序的启动线程Main线程

1.3.3 Reactor线程的启动

接下来执行,Reactor线程的启动是在向Reactor提交第一个异步任务的时候启动的。

eventLoop.execute(new Runnable() {
    @Override
    public void run() {
        //将channel注册selector上,事件默认0,将accept和父handler注册到pipe,以及剔除初始化的handler
        register0(promise);
    }
});
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
@Override
public void execute(Runnable task) {
    ObjectUtil.checkNotNull(task, "task");
    //任务是否是排队执行还是立即执行
    execute(task, !(task instanceof LazyRunnable) && wakesUpForTask(task));
}
  
      private void execute(Runnable task, boolean immediate) {
        //1.当前线程是否为Reactor线程
        boolean inEventLoop = inEventLoop();
        //2.将任务添加到队列,如果当前实例已经关闭,则拒绝。
        addTask(task);
        if (!inEventLoop) {
            //3.如果当前线程不是Reactor线程,则启动Reactor线程
            //这里可以看出Reactor线程的启动是通过 向NioEventLoop添加异步任务时启动的
            //标记线程启用,当没任务时,调用select(),等待事件连接
            startThread();
            if (isShutdown()) {
                boolean reject = false;
                try {
                    if (removeTask(task)) {
                        reject = true;
                    }
                } catch (UnsupportedOperationException e) {
                    // The task queue does not support removal so the best thing we can do is to just move on and
                    // hope we will be able to pick-up the task before its completely terminated.
                    // In worst case we will log on termination.
                }
                if (reject) {
                    reject();
                }
            }
        }
        //immediate:提交的task需要立即执行
        //addTaskWakesUp:true 表示当且仅当只有调用addTask方法时才会唤醒Reactor线程。调用别的方法并不会唤醒Reactor线程。
                    // 在初始化NioEventLoop时会设置为false,表示并不是只有addTask方法才能唤醒Reactor线程 还有其他方法可以唤醒Reactor线程,
                    // 比如这里的execute方法就会唤醒Reactor线程。
        if (!addTaskWakesUp && immediate) {
            //4.将Reactor线程从Selector上唤醒
            wakeup(inEventLoop);
        }
    }
}
  1. 将任务添加到队列
  2. 如果当前线程不是Reactor线程,则启动Reactor线程。此时当前线程为main线程。所以这里会启动reactor线程。
1.3.4 startThread
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
  
    //Reactor线程状态  初始为 未启动状态
    private volatile int state = ST_NOT_STARTED;
  
      //定义Reactor线程状态
    private static final int ST_NOT_STARTED = 1;
    private static final int ST_STARTED = 2;
    private static final int ST_SHUTTING_DOWN = 3;
    private static final int ST_SHUTDOWN = 4;
    private static final int ST_TERMINATED = 5;
  
      //Reactor线程状态字段state 原子更新器
    private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
            AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "state");
  
private void startThread() {
    if (state == ST_NOT_STARTED) {
        if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
            boolean success = false;
            try {
                //Reactor线程开始启动
                doStartThread();
                success = true;
            } finally {
                //启动失败回滚状态
                if (!success) {
                    STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
                }
            }
        }
    }
}
  
}
  • Reactor线程初始化状态为ST_NOT_STARTED,首先CAS更新状态为ST_STARTED
  • doStartThread启动Reactor线程
  • 启动失败的话,需要将Reactor线程状态改回ST_NOT_STARTED
private final Executor executor;
private void doStartThread() {
    assert thread == null;
    executor.execute(new Runnable() {
        @Override
        public void run() {
      .....
                //Reactor线程开始启动
                SingleThreadEventExecutor.this.run();
             .....
        }
    });
}
  • Reactor线程的核心工作之前介绍过:轮询所有注册其上的Channel中的IO就绪事件处理对应Channel上的IO事件执行异步任务。Netty将这些核心工作封装在io.netty.channel.nio.NioEventLoop#run方法中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • NioEventLoop#run封装在异步任务中,提交给executor执行,Reactor线程至此开始工作了就。
public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;
@Override
public void execute(Runnable command) {
    //启动Reactor线程
    threadFactory.newThread(command).start();
}

}

此时Reactor线程已经启动,后面的工作全部都由这个Reactor线程来负责执行了。

而用户启动线程在向Reactor提交完NioServerSocketChannel的注册任务register0后,就逐步退出调用堆栈,回退到最开始的启动入口处ChannelFuture f = b.bind(PORT).sync()

此时Reactor中的任务队列中只有一个任务register0Reactor线程启动后,会从任务队列中取出任务执行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.3.5 register0
        //是否从未注册过
        private boolean neverRegistered = true;
    //标记是否注册
    private volatile boolean registered;

 private void register0(ChannelPromise promise) {
            try {
                // check if the channel is still open as it could be closed in the mean time when the register
                // call was outside of the eventLoop
                //1.查看注册操作是否已经取消,或者通道是否仍然打开,因为它可能在注册调用在 eventLoop 之外的同时关闭
                if (!promise.setUncancellable() || !ensureOpen(promise)) {
                    return;
                }
                //如果频道从未注册过,则为 true,否则为 false
                boolean firstRegistration = neverRegistered;
                //2.channel注册选择器上
                doRegister();
                //标记注册过
                neverRegistered = false;
                registered = true;

                // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
                // user may already fire events through the pipeline in the ChannelFutureListener.
                //3.初始化channelPipeline,回调pipeline中添加的ChannelInitializer的handlerAdded方法
                //主要将accept和父handler注册到pipe,以及剔除初始化的handler
                pipeline.invokeHandlerAddedIfNeeded();

                //4.设置regFuture为success,触发operationComplete回调,将bind操作放入Reactor的任务队列中,等待Reactor线程执行。
                //会触发io.netty.channel.ChannelFutureListener#operationComplete,进行端口绑定
                safeSetSuccess(promise);
                //5.通道注册完成后,成功绑定NioEventLoop线程后,会调用fireChannelRegistered,触发通道注册事件
                pipeline.fireChannelRegistered();
                // Only fire a channelActive if the channel has never been registered. This prevents firing
                // multiple channel actives if the channel is deregistered and re-registered.
                //对于服务端ServerSocketChannel来说 只有绑定端口地址成功后 channel的状态才是active的。
                //此时绑定操作作为异步任务在Reactor的任务队列中,绑定操作还没开始,所以这里的isActive()是false
                if (isActive()) {
                    //6.当通道激活完成后(所有的业务处理器添加,注册的异步任务完成,并且NioEventLoop线程绑定的异步任务完成),会调用fireChannelActive,触发通道激活事件
                    if (firstRegistration) {
                        //触发channelActive事件
                        pipeline.fireChannelActive();
                    } else if (config().isAutoRead()) {
                        // This channel was registered before and autoRead() is set. This means we need to begin read
                        // again so that we process inbound data.
                        //
                        // See https://github.com/netty/netty/issues/4805
                        beginRead();
                    }
                }
            } catch (Throwable t) {
                // Close the channel directly to avoid FD leak.
                closeForcibly();
                closeFuture.setClosed();
                safeSetFailure(promise, t);
            }
        }
  • 查看注册操作是否已经取消,或者通道是否仍然打开,因为它可能在注册调用在 eventLoop 之外的同时关闭

  • channel注册选择器上

  • 初始化channelPipeline,回调pipeline中添加的ChannelInitializer的handlerAdded方法

  • 设置regFuture为success,触发operationComplete回调,将bind操作放入Reactor的任务队列中,等待Reactor线程执行。

  • 通道注册完成后,成功绑定NioEventLoop线程后,会调用fireChannelRegistered,触发通道注册事件

  • 当通道激活完成后(所有的业务处理器添加,注册的异步任务完成,并且NioEventLoop线程绑定的异步任务完成),会调用fireChannelActive,触发通道激活事件

1.3.6 doRegister()
public abstract class AbstractNioChannel extends AbstractChannel {
      @Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
                //注册选择器,并将chanle封装到附件,并将selectionKey保存channel中
                selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
                return;
            } catch (CancelledKeyException e) {
                if (!selected) {
                    // Force the Selector to select now as the "canceled" SelectionKey may still be
                    // cached and not removed because no Select.select(..) operation was called yet.
                    eventLoop().selectNow();
                    selected = true;
                } else {
                    // We forced a select operation on the selector before but the SelectionKey is still cached
                    // for whatever reason. JDK bug ?
                    throw e;
                }
            }
        }
    }
 
}

调用jdk 原生选择器将channel注册上去,并将netty封装的channel作为附件。

1.3.7 HandlerAdded事件回调中初始化ChannelPipeline

NioServerSocketChannel注册到Main Reactor上的Selector后,Netty通过调用pipeline.invokeHandlerAddedIfNeeded()开始回调NioServerSocketChannelpipeline里的ChannelHandler的handlerAdded方法

此时NioServerSocketChannelpipeline结构如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
      //因为init是全局共享的,所以通过initMap来存储已经初始化的pipeline,避免重复创建
    private final Set<ChannelHandlerContext> initMap = Collections.newSetFromMap(
            new ConcurrentHashMap<ChannelHandlerContext, Boolean>());
  
      @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        if (ctx.channel().isRegistered()) {
            if (initChannel(ctx)) {
                removeState(ctx);
            }
        }
    }

      private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
        if (initMap.add(ctx)) { // Guard against re-entrance.
            try {
                //执行初始化handler方法,将父handler添加到pipe,以及ServerBootstrapAcceptor
                initChannel((C) ctx.channel());
            } catch (Throwable cause) {
                // Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
                // We do so to prevent multiple calls to initChannel(...).
                exceptionCaught(ctx, cause);
            } finally {
                ChannelPipeline pipeline = ctx.pipeline();
                if (pipeline.context(this) != null) {
                    //如果包含当前handler,则删除当前handler
                    pipeline.remove(this);
                }
            }
            return true;
        }
        return false;
    }

      protected abstract void initChannel(C ch) throws Exception;
  
  
      private void removeState(final ChannelHandlerContext ctx) {
        //从initMap防重Set集合中删除ChannelInitializer
        if (ctx.isRemoved()) {
            initMap.remove(ctx);
        } else {
            ctx.executor().execute(new Runnable() {
                @Override
                public void run() {
                    initMap.remove(ctx);
                }
            });
        }
    }
}
  • 首先查看channel是否注册了,注册了则执行匿名类中initChannel逻辑。
p.addLast(new ChannelInitializer<Channel>() {
    @Override
    public void initChannel(final Channel ch) {
        final ChannelPipeline pipeline = ch.pipeline();
        //获取Main Reactor handler
        ChannelHandler handler = config.handler();
        if (handler != null) {
            //MainReactor handler添加到pipe
            pipeline.addLast(handler);
        }

        //这里为什么不干脆直接将ChannelHandler添加到pipeline中,而是又使用到了ChannelInitializer呢?
        //其实原因有两点:
        //为了保证线程安全地初始化pipeline,所以初始化的动作需要由Reactor线程进行,而当前线程是用户程序的启动Main线程 并不是Reactor线程。这里不能立即初始化。
        //初始化Channel中pipeline的动作,需要等到Channel注册到对应的Reactor中才可以进行初始化,当前只是创建好了NioServerSocketChannel,但并未注册到Main Reactor上。
        //初始化NioServerSocketChannel中pipeline的时机是:当NioServerSocketChannel注册到Main Reactor之后,绑定端口地址之前。

        //在该初始化回调方法中,添加LoggingHandler是直接向pipeline中添加,而添加Acceptor为什么不是直接添加而是封装成异步任务呢?
        ch.eventLoop().execute(new Runnable() {
            @Override
            public void run() {//管道添加ServerBootstrapAcceptor
                pipeline.addLast(new ServerBootstrapAcceptor(
                        ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
            }
        });
    }
});
  • 当执行完initChannel 方法后,ChannelPipeline的初始化就结束了,此时ChannelInitializer就没必要再继续呆在pipeline中了,所需要将ChannelInitializerpipeline中删除。pipeline.remove(this)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.3.8 回调regFuture的ChannelFutureListener

执行initAndRegister是一个异步的过程,所以在initAndRegister()方法调用后返回一个代表注册结果的ChannelFuture regFuture

private ChannelFuture doBind(final SocketAddress localAddress) {
  
  .......
 //2.任务完成则绑定端口
        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);
            //3.如果此时注册操作没有完成,则向regFuture添加operationComplete回调函数,注册成功后回调。
            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();
                        //socket绑定地址
                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
  
  ..........
}

之后会向ChannelFuture regFuture添加一个注册完成后的回调函数 ChannelFutureListener。在回调函数operationComplete中开始发起绑端口地址流程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

那么这个回调函数在什么时候?什么地方发起的呢??

让我们在回到本小节的主题register0方法的流程中:

当调用doRegister()方法完成NioServerSocketChannelMain Reactor的注册后,紧接着会调用pipeline.invokeHandlerAddedIfNeeded()方法中触发ChannelInitializer#handlerAdded回调中对pipeline进行初始化。

最后在safeSetSuccess方法中,开始回调注册在regFuture上的ChannelFutureListener

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
       protected final void safeSetSuccess(ChannelPromise promise) {
            if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
                logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
            }
        }
}

public class DefaultChannelPromise extends DefaultPromise<Void> implements ChannelPromise, FlushCheckpoint {
  
      @Override
    public boolean trySuccess() {
        return trySuccess(null);
    }
  
      @Override
    public boolean trySuccess(V result) {
        return setSuccess0(result);
    }
  
      private boolean setSuccess0(V result) {
        return setValue0(result == null ? SUCCESS : result);
    }
  
      private boolean setValue0(Object objResult) {
        if (RESULT_UPDATER.compareAndSet(this, null, objResult) ||
            RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
            if (checkNotifyWaiters()) {
                //回调注册在promise上的listeners
                notifyListeners();
            }
            return true;
        }
        return false;
    }
}

regFuture设置为success后然后回调所有监听器。

2. doBind0

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
  
private static void doBind0(
        final ChannelFuture regFuture, final Channel channel,
        final SocketAddress localAddress, final ChannelPromise promise) {

    // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
    // the pipeline in its channelRegistered() implementation.
    channel.eventLoop().execute(new Runnable() {
        @Override
        public void run() {
            if (regFuture.isSuccess()) {
                //绑定地址,并添加channel关闭事件
                channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            } else {
                promise.setFailure(regFuture.cause());
            }
        }
    });
}
  
}

这里Netty又将绑定端口地址的操作封装成异步任务,提交给Reactor执行。

但是这里有一个问题,其实此时执行doBind0方法的线程正是Reactor线程,那为什么不直接在这里去执行bind操作,而是再次封装成异步任务提交给Reactor中的taskQueue呢?

反正最终都是由Reactor线程执行,这其中又有什么分别呢?

经过上小节的介绍我们知道,bind0方法的调用是由io.netty.channel.AbstractChannel.AbstractUnsafe#register0方法在将NioServerSocketChannel注册到Main Reactor之后,并且NioServerSocketChannelpipeline已经初始化完毕后,通过safeSetSuccess方法回调过来的。

这个过程全程是由Reactor线程来负责执行的,但是此时register0方法并没有执行完毕,还需要执行后面的逻辑。

而绑定逻辑需要在注册逻辑执行完之后执行,所以在doBind0方法中Reactor线程会将绑定操作封装成异步任务先提交给taskQueue中保存,这样可以使Reactor线程立马从safeSetSuccess中返回,继续执行剩下的register0方法逻辑。

private void register0(ChannelPromise promise) {
   ................省略............
     
        doRegister();
        pipeline.invokeHandlerAddedIfNeeded();
        //4.设置regFuture为success,触发operationComplete回调,将bind操作放入Reactor的任务队列中,等待Reactor线程执行。
        //会触发io.netty.channel.ChannelFutureListener#operationComplete,进行端口绑定
        safeSetSuccess(promise);
        //5.通道注册完成后,成功绑定NioEventLoop线程后,会调用fireChannelRegistered,触发通道注册事件
        pipeline.fireChannelRegistered();
   ................省略............
     
}

Reactor线程执行完register0方法后,就会从taskQueue中取出异步任务执行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • Reactor线程会先取出位于taskQueue队首的任务执行,这里是指向NioServerSocketChannelpipeline中添加ServerBootstrapAcceptor的异步任务。

    此时NioServerSocketChannelpipeline的结构如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 接着Reactor线程执行绑定任务。

3. 绑定端口地址

Channel的操作行为全部定义在ChannelOutboundInvoker接口中

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

public interface ChannelOutboundInvoker {
      ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise);
    ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise);
}

AbstractChannel实现bind方法

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    return pipeline.bind(localAddress, promise);
}
}

调用pipeline.bind(localAddress, promise)pipeline中传播bind事件,触发回调pipeline中所有ChannelHandlerbind方法

事件在pipeline中的传播具有方向性:

  • inbound事件HeadContext开始逐个向后传播直到TailContext
  • outbound事件则是反向传播,从TailContext开始反向向前传播直到HeadContext

inbound事件只能被pipeline中的ChannelInboundHandler响应处理outbound事件只能被pipeline中的ChannelOutboundHandler响应处理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然而这里的bind事件在Netty中被定义为outbound事件,所以它在pipeline中是反向传播。先从TailContext开始反向传播直到HeadContext。然而bind的核心逻辑也正是实现在HeadContext中。

public class DefaultChannelPipeline implements ChannelPipeline {
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    return tail.bind(localAddress, promise);
}
}

3.1 HeadContext

    final class HeadContext extends AbstractChannelHandlerContext
            implements ChannelOutboundHandler, ChannelInboundHandler {
@Override
public void bind(
        ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
    unsafe.bind(localAddress, promise);
}
      
    }

调用channel的unsafe对象实现bind

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
      protected abstract void doBind(SocketAddress localAddress) throws Exception;
  
      protected abstract class AbstractUnsafe implements Unsafe {
             @Override
        public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
            assertEventLoop();

            if (!promise.setUncancellable() || !ensureOpen(promise)) {
                return;
            }

            // See: https://github.com/netty/netty/issues/576
            //查看是否广播
            if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) &&
                localAddress instanceof InetSocketAddress &&
                !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() &&
                !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
                // Warn a user about the fact that a non-root user can't receive a
                // broadcast packet on *nix if the socket is bound on non-wildcard address.
                logger.warn(
                        "A non-root user can't receive a broadcast packet if the socket " +
                        "is not bound to a wildcard address; binding to a non-wildcard " +
                        "address (" + localAddress + ") anyway as requested.");
            }
            //查看该socket是否连接,这个时候还未激活。
            boolean wasActive = isActive();
            try {
                //绑定地址
                doBind(localAddress);
            } catch (Throwable t) {
                safeSetFailure(promise, t);
                closeIfClosed();
                return;
            }
/*            那么为何不直接触发pipeline中的ChannelActive事件而是又封装成异步任务呢??
            因为如果直接在这里触发ChannelActive事件,那么Reactor线程就会去执行pipeline中的ChannelHandler的channelActive事件回调。
            这样的话就影响了safeSetSuccess(promise)的执行,延迟了注册在promise上的ChannelFutureListener的回调。*/
            if (!wasActive && isActive()) {
                //当通道激活完成后(所有的业务处理器添加,注册的异步任务完成,并且NioEventLoop线程绑定的异步任务完成),会调用fireChannelActive,触发通道激活事件
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        //注册accept事件
                        pipeline.fireChannelActive();
                    }
                });
            }
            //回调注册在promise上的ChannelFutureListener
            safeSetSuccess(promise);
        }
        
      }
}

执行NioServerSocketChannel类的doBind进行绑定

    protected void doBind(SocketAddress localAddress) throws Exception {
        //调用jdk原生bind方法
        if (PlatformDependent.javaVersion() >= 7) {
            javaChannel().bind(localAddress, config.getBacklog());
        } else {
            javaChannel().socket().bind(localAddress, config.getBacklog());
        }
    }
  • 判断是否为首次绑定,如果是的话将触发pipeline中的ChannelActive事件封装成异步任务放入Reactor中的taskQueue中。
  • 执行safeSetSuccess(promise),回调注册在promise上的ChannelFutureListener

还是同样的问题,当前执行线程已经是Reactor线程了,那么为何不直接触发pipeline中的ChannelActive事件而是又封装成异步任务呢??

因为如果直接在这里触发ChannelActive事件,那么Reactor线程就会去执行pipeline中的ChannelHandlerchannelActive事件回调

这样的话就影响了safeSetSuccess(promise)的执行,延迟了注册在promise上的ChannelFutureListener的回调。

到现在为止,Netty服务端就已经完成了绑定端口地址的操作,NioServerSocketChannel的状态现在变为Active

最后还有一件重要的事情要做,我们接着来看pipeline中对channelActive事件处理。

3.2 channelActive事件处理

Active事件在Netty中定义为inbound事件,所以它在pipeline中的传播为正向传播,从HeadContext一直到TailContext为止。

channelActive事件回调中需要触发向Selector指定需要监听的IO事件~~OP_ACCEPT事件

final class HeadContext extends AbstractChannelHandlerContext
        implements ChannelOutboundHandler, ChannelInboundHandler {
                @Override
        public void channelActive(ChannelHandlerContext ctx) {
            //pipeline中继续向后传播channelActive事件
            //触发通道激活事件
            ctx.fireChannelActive();
            //如果是autoRead 则自动触发read事件传播
            //在read回调函数中 触发OP_ACCEPT注册
            //注册accept事件
            readIfIsAutoRead();
        }
  
            private void readIfIsAutoRead() {
            //如果是autoRead 则触发read事件传播,默认为true
            if (channel.config().isAutoRead()) {
                //selector 注册accept事件
                channel.read();
            }
        }
  
}

接着触发read事件

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
@Override
public Channel read() {
    pipeline.read();
    return this;
}
}

read事件在Netty中定义为outbound事件,所以它在pipeline中的传播为正向传播,从TailContext 一直到HeadContext为止。

    final class HeadContext extends AbstractChannelHandlerContext
            implements ChannelOutboundHandler, ChannelInboundHandler {
@Override
public void read(ChannelHandlerContext ctx) {
    //触发注册OP_ACCEPT或者OP_READ事件
    unsafe.beginRead();
}
}
  • HeadContext中的channelActive回调中触发pipeline中的read事件
  • read事件再次传播到HeadContext时,触发HeadContext#read方法的回调。在read回调中调用channel底层操作类unsafebeginRead方法向selector注册监听OP_ACCEPT事件

3.3 beginRead

protected abstract class AbstractUnsafe implements Unsafe {
@Override
public final void beginRead() {
    //断言判断执行该方法的线程必须是Reactor线程。
    assertEventLoop();

    //channel必须是Active
    if (!isActive()) {
        return;
    }

    try {
        //注册accept事件,触发在selector上注册channel感兴趣的监听事件
        doBeginRead();
    } catch (final Exception e) {
        invokeLater(new Runnable() {
            @Override
            public void run() {
                pipeline.fireExceptionCaught(e);
            }
        });
        close(voidPromise());
    }
}

    }

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
      protected abstract void doBeginRead() throws Exception;
}
  • 断言判断执行该方法的线程必须是Reactor线程。
  • 判断channel是否为活跃状态,此时channel已经绑定端口了,处于活跃状态。
  • 注册accept事件,触发在selector上注册channel感兴趣的监听事件
public abstract class AbstractNioChannel extends AbstractChannel {
    volatile SelectionKey selectionKey;
    boolean readPending;
    // Channel监听事件集合 这里是SelectionKey.OP_ACCEPT事件
    protected final int readInterestOp;
@Override
protected void doBeginRead() throws Exception {
    // Channel.read() or ChannelHandlerContext.read() was called
    final SelectionKey selectionKey = this.selectionKey;
    //查看SelectionKey是否有效
    if (!selectionKey.isValid()) {
        return;
    }

    readPending = true;

    final int interestOps = selectionKey.interestOps();
    if ((interestOps & readInterestOp) == 0) {
        //注册accept事件
        selectionKey.interestOps(interestOps | readInterestOp);
    }
}
}
  • NioServerSocketChannel在向Main Reactor中的Selector注册后,会获得一个SelectionKey。这里首先要获取这个SelectionKey
  • SelectionKey中获取NioServerSocketChannel感兴趣的IO事件集合 interestOps,当时在注册的时候interestOps设置为0
  • 将在NioServerSocketChannel初始化时设置的readInterestOp = OP_ACCEPT,设置到SelectionKey中的interestOps集合中。这样Reactor中的Selector就开始监听interestOps集合中包含的IO事件了。

此时Main Reactor中主要监听的是OP_ACCEPT事件

流程图如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此时Netty的Reactor模型结构如下:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值