• 01NioSocketChannel笔记


    1.在NioSocketChannel里面直接从java的SelectorProvider里面拿到SelectorProvider
    private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
    2.在创建NioSocketChannel的时候会创建一个, NioSocketChannel会把NioSocketChannel和socke传入
    public NioSocketChannel(Channel parent, SocketChannel socket) {
    super(parent, socket);
    config = new NioSocketChannelConfig(this, socket.socket());
    }

    3.newUnsafe调用的是NioSocketChannel的newUnsafe方法,返回的是NioSocketChannelUnsafe的类
    protected AbstractNioUnsafe newUnsafe() {
    return new NioSocketChannelUnsafe();
    }

    4.newPipeline会把当前的NioSocketChannel传入进去
    protected DefaultChannelPipeline newChannelPipeline() {
    return new DefaultChannelPipeline(this);
    }

    在DefaultChannelPipeline里面会创建AbstractChannelHandlerContext 双向链表head和tail
    protected DefaultChannelPipeline(Channel 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;
    }

    head和tail里面传入的this是DefaultChannelPipeline
    链表中 head 是一个 ChannelOutboundHandler, 而 tail 则是一个 ChannelInboundHandler.
    接着看一下 HeadContext 的构造器:

    HeadContext(DefaultChannelPipeline pipeline) {
    super(pipeline, null, HEAD_NAME, false, true);
    unsafe = pipeline.channel().unsafe();
    }

    ----------
    第二部分是NioEventLoopGroup

    1.NioEventLoop 有几个重载的构造器, 不过内容都没有什么大的区别, 最终都是调用的父类MultithreadEventLoopGroup构造器:

    protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
    super(nThreads == 0? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
    }
    在MultithreadEventLoopGroup里面定义

    DEFAULT_EVENT_LOOP_THREADS是取cpu处理器的个数*2

    private static final int DEFAULT_EVENT_LOOP_THREADS;

    static {
    DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
    "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

    if (logger.isDebugEnabled()) {
    logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
    }
    }

    2.在 MultithreadEventExecutorGroup里面定义EventExecutor数据 children,
    EventExecutorChooserFactory.EventExecutorChooser chooser;

    EventExecutorChooserFactory chooserFactory 是在
    DefaultEventExecutorChooserFactory.INSTANCE 创建的
    public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();

    public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {

    private final EventExecutor[] children;
    private final Set<EventExecutor> readonlyChildren;
    private final AtomicInteger terminatedChildren = new AtomicInteger();
    private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
    private final EventExecutorChooserFactory.EventExecutorChooser chooser;

    在 MultithreadEventExecutorGroup构造函数中,创建 children = EventExecutor[nThreads];
    主要做了两件事,对children的每一个元素创建一个newchild
    第二是chooserFactory.newChooser方法创建一个EventExecutorChooser

    protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
    EventExecutorChooserFactory chooserFactory, Object... args) {

    children = new EventExecutor[nThreads];

    for (int i = 0; i < nThreads; i ++) {
    boolean success = false;
    try {
    children[i] = newChild(executor, args);
    success = true;
    }
    }

    chooser = chooserFactory.newChooser(children);

    final FutureListener<Object> terminationListener = new FutureListener<Object>() {
    @Override
    public void operationComplete(Future<Object> future) throws Exception {
    if (terminatedChildren.incrementAndGet() == children.length) {
    terminationFuture.setSuccess(null);
    }
    }
    };

    for (EventExecutor e: children) {
    e.terminationFuture().addListener(terminationListener);
    }

    Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
    Collections.addAll(childrenSet, children);
    readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }


    3.在 chooser = chooserFactory.newChooser(children); 实现方法

    public EventExecutorChooser newChooser(EventExecutor[] executors) {
    if (isPowerOfTwo(executors.length)) {
    return new PowerOfTwoEventExecutorChooser(executors);
    } else {
    return new GenericEventExecutorChooser(executors);
    }
    }

    4.熟悉EventExcutor之前,要知道Excutor是线程池的老祖宗
    ThreadPoolExecutor用来创建线程池的,都是通过攻击类Excutors来创建的
    比如
    public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
    0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>());
    }

    EventExcutor是从ScheduledExecutorService里面派生出来的接口
    public interface EventExecutorGroup extends ScheduledExecutorService, Iterable<EventExecutor>

    5.在 children[i] = newChild(executor, args); 的时候,调用的是NIOEventLoopGroup的newChild方法

    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    return new NioEventLoop(this, executor, (SelectorProvider) args[0],
    ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
    }

    返回的是一个NioEventLoop对象,NIOEventLoopGroup是继承了SingleThreadEventLoop的

    public final class NioEventLoop extends SingleThreadEventLoop

    SinleThreadEventLoop 这个单线程池是实现了EventExcutor接口,还继承了 AbstractExecutorService
    public abstract class AbstractEventExecutor extends AbstractExecutorService implements EventExecutor

    AbstractExecutorService 就是线程池 ThreadPoolExecutor 的父类

    6.总结
    最后总结一下整个 EventLoopGroup 的初始化过程吧:

    EventLoopGroup(其实是MultithreadEventExecutorGroup) 内部维护一个类型为 EventExecutor children 数组, 其大小是 nThreads, 这样就构成了一个线程池

    如果我们在实例化 NioEventLoopGroup 时, 如果指定线程池大小, 则 nThreads 就是指定的值, 反之是处理器核心数 * 2

    MultithreadEventExecutorGroup 中会调用 newChild 抽象方法来初始化 children 数组

    抽象方法 newChild 是在 NioEventLoopGroup 中实现的, 它返回一个 NioEventLoop 实例.

    NioEventLoop 属性:

    SelectorProvider provider 属性: NioEventLoopGroup 构造器中通过 SelectorProvider.provider() 获取一个 SelectorProvider

    Selector selector 属性: NioEventLoop 构造器中通过调用通过 selector = provider.openSelector() 获取一个 selector 对象.


    -----------------

    第三部分 channel的初始化和注册
    1.channel注册是注入到selector里面的, 在bootStrap里面调用的
    final ChannelFuture initAndRegister() {
    Channel channel = null;
    channel = channelFactory.newChannel();
    init(channel);

    ChannelFuture regFuture = config().group().register(channel);
    if (regFuture.cause() != null) {
    if (channel.isRegistered()) {
    channel.close();
    } else {
    channel.unsafe().closeForcibly();
    }
    }

    return regFuture;
    }


    2.在 ChannelFuture regFuture = config().group().register(channel);

    config是BootStrap里面定义的, 然后把自己bootstrap当做参数传入进去的
    private final BootstrapConfig config = new BootstrapConfig(this);

    group方法就是返回的就是EventLoopGroup
    public final EventLoopGroup group() {
    return group;
    }

    register调用的是MultithreadEventLoopGroup类的,
    他是NIOEventLoopGroup的父类, 你放在bootStrap里面的是NIOEventLoopGroup对象

    public ChannelFuture register(Channel channel) {
    return next().register(channel);
    }

    next方法是MultithreadEventExecutorGroup类的
    public EventExecutor next() {
    return chooser.next();
    }

    调用的是chooser的next方法, chooser是在 MultithreadEventExecutorGroup的构造函数中创建的
    参数是children也就是EventExcutor数组,这个EventExcutor的实现类是NioEventLoop
    NioEventLoop 是 SingleThreadEventLoop类的子类

    chooser = chooserFactory.newChooser(children);

    next方法最终的调用是PowerOfTwoEventExecutorChooser类或者是GenericEventExecutorChooser

    PowerOfTwoEventExecutorChooser类的
    public EventExecutor next() {
    return executors[idx.getAndIncrement() & executors.length - 1];
    }

    GenericEventExecutorChooser类的
    private static final class GenericEventExecutorChooser implements EventExecutorChooser {


    @Override
    public EventExecutor next() {
    return executors[Math.abs(idx.getAndIncrement() % executors.length)];
    }

    }

    每一次调用next方法,idx索引值都会自增,从0开始
    register方法是在 SingleThreadEventLoop类的

    public ChannelFuture register(Channel channel) {
    return register(new DefaultChannelPromise(channel, this));
    }

    DefaultChannelPromise持有两个参数对象NioEventLoop和NioSocketChannel
    channel是在BootStrap里面传入进去的NioSocketChannel类创建出来的实例
    this 对象是NioEventLoop
    new DefaultChannelPromise(channel, this);

    public ChannelFuture register(final ChannelPromise promise) {
    ObjectUtil.checkNotNull(promise, "promise");
    promise.channel().unsafe().register(this, promise);
    return promise;
    }

    这个register是AbstractUnsafe的register,是从NioSocketChannel里面拿出来的
    promise.channel().unsafe().register(this, promise);

    public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    if (eventLoop == null) {
    throw new NullPointerException("eventLoop");
    }
    if (isRegistered()) {
    promise.setFailure(new IllegalStateException("registered to an event loop already"));
    return;
    }
    if (!isCompatible(eventLoop)) {
    promise.setFailure(
    new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
    return;
    }
    //上面这些都是抛异常的方法

    AbstractChannel.this.eventLoop = eventLoop;

    if (eventLoop.inEventLoop()) {
    register0(promise);
    } else {
    try {
    eventLoop.execute(new Runnable() {
    @Override
    public void run() {
    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);
    }
    }
    }

    inEventLoop是判断当前的线程是否等于SingleThreadEventExecutor类的thread
    public boolean inEventLoop() {
    return inEventLoop(Thread.currentThread());
    }

    SingleThreadEventExecutor类的
    public boolean inEventLoop(Thread thread) {
    return thread == this.thread;
    }


    3.调用register0方法
    DefaultChannelPromise持有两个参数对象NioEventLoop和NioSocketChannel

    register0是AbstractUnsafe这个类的,
    AbstractUnsafe.register0

    但是它里面调用的doRegister方法是 AbstractChannel.doRegister() 的,就是回调方法
    AbstractUnsafe是AbstractChannel的内部类

    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
    if (!promise.setUncancellable() || !ensureOpen(promise)) {
    return;
    }
    boolean firstRegistration = neverRegistered;
    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.
    pipeline.invokeHandlerAddedIfNeeded();

    safeSetSuccess(promise);
    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.
    if (isActive()) {
    if (firstRegistration) {
    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);
    }
    }

    调用NioSocketChannel类的doRegister方法,这个是在他的父类 AbstractNioChannel
    eventLoop()返回的是NioEventLoop对象,这个是在register方法里面注册的
    AbstractChannel.this.eventLoop = eventLoop;

    protected void doRegister() throws Exception {
    boolean selected = false;
    for (;;) {
    try {
    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;
    }
    }
    }
    }

    javachannel是在创建NioSocketChannel的时候创建的SocketChannel
    EventLoop().unwrappedSelector()从NioEventLoop里面,就是EventExcutor数组里面
    也就是线程池里面取出selector
    0是对任务事件都不感兴趣
    this把NioSocketChannel当做附件
    javaChannel().register(eventLoop().unwrappedSelector(), 0, this);


    总结:
    我们总结一下 Channel 的注册过程:

    首先在 AbstractBootstrap.initAndRegister中, 通过 group().register(channel), 调用 MultithreadEventLoopGroup.register 方法

    在MultithreadEventLoopGroup.register 中, 通过 next() 获取一个可用的 SingleThreadEventLoop, 然后调用它的 register

    在 SingleThreadEventLoop.register 中, 通过 channel.unsafe().register(this, promise) 来获取 channel 的 unsafe() 底层操作对象, 然后调用它的 register.

    在 AbstractUnsafe.register 方法中, 调用 register0 方法注册 Channel

    在 AbstractUnsafe.register0 中, 调用 AbstractNioChannel.doRegister 方法

    AbstractNioChannel.doRegister 方法通过 javaChannel().register(eventLoop().selector, 0, this) 将 Channel 对应的 Java NIO SockerChannel 注册到一个 eventLoop 的 Selector 中, 并且将当前 Channel 作为 attachment.

    总的来说, Channel 注册过程所做的工作就是将 Channel 与对应的 EventLoop 关联,
    因此这也体现了, 在 Netty 中, 每个 Channel 都会关联一个特定的 EventLoop,
    并且这个 Channel 中的所有 IO 操作都是在这个 EventLoop 中执行的; 当关联好 Channel 和 EventLoop 后,
    会继续调用底层的 Java NIO SocketChannel 的 register 方法, 将底层的 Java NIO SocketChannel 注册到指定的 selector 中.
    通过这两步, 就完成了 Netty Channel 的注册过程.

    --------

  • 相关阅读:
    五、敏捷开发框架 初识组件式开发
    winform 控制Text Box只能输入英文数字和退格键
    WPF 常用控件属性
    问题分析
    串口通讯学习
    解决MVC中Model上的特性在EF框架刷新时清空的问题
    论序列化与反序列化
    dynamics 365 安全角色及权限
    .NET Core 依赖注入框架 框图笔记
    C#基本类型的取值范围与 .NET框架类型的对应
  • 原文地址:https://www.cnblogs.com/handsome1013/p/10002835.html
Copyright © 2020-2023  润新知