zoukankan      html  css  js  c++  java
  • 从源码角度解析Netty的React模式是如何工作的

    Netty 支持多种实现方式,比如nio,epoll 等,本文以nio的实现方式进行讲解。

    1.EventLoop :

    事件循环看,简单来说就是一个死循环监听事件,如果事件来了,处理掉。通常做法就是开启一个独立线程,一直循环。

    伪代码:

    while (queue.waitForMessage()) {
    queue.processNextMessage();
    }

    2.EventLoopGroup: 

    一组(多个)事件循环。

    3.bossGroup 和 workGroup

    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();

    server端bossGroup 是负责 NioServerSocketChannel 处理客户端连接请求的,一个应用程序如果只开了一个端口(严格来说就是没有多个ServerBootstrap公用一个
    bossGroup),那么 bossGroup 只需要一个eventLoop 就行了,如果配置大于1也没关系(因为用不到,eventLoop也不会启动)

    ServerSocketChannel 创建好后,就绑定到网络端口就开始监听,如果有新的客户端连接进来,那么accept()后就会产生 SocketChannel,一个连接对应一个 SocketChannel

    伪代码:

    ServerSocketChannel ssc = ServerSocketChannel.open();
    ...
    SocketChannel socketChannel = ssc.accept();

    为了提高服务器性能,所有有的
    SocketChannel 的相关操作都是在workGroup中完成的,所以 workGroup 里面需要配置适当多个 EnventLoop.

    4.源码层面讲解 一个  ServerSocketChannel  只需要一个  EventLoop.

    ->bind(100).sync();  绑定端口

    -->AbstractBootstrap.doBind  具体绑定动作

    ---->AbstractBootstrap.initAndRegister     config().group().register(channel);   将 serverChannel注册到bossGroup 的某个eventLoop中

    ------>MultithreadEventLoopGroup.register    next().register(channel);     next() 方法负责从group 中挑选一个eventLoop ,具体是由 chooser.next()实现;

    通俗来讲就是,创建一个serverChannel绑定端口,初始化端口的过程中是从bossGroup中挑选一个 eventLoop,将channel注册到eventLoop中,eventLoop中nio selector,完成channel的注册。

    注册的核心代码是:

    如果当前线程就是在enventLoop ,调用register 方法就是直接执行register0,否则向线程(池)提交一个任务(eventLoop.execute()),这就是Reactor模式的核心实现逻辑,通过任务完成线程调配。

    提交任务时候会干什么呢?

    以上完整过程具体来讲就是,main线程开启(创建)一个serverChannel,创建过程中会从bossGroup 中选择一个eventLoop 给该channel, 同时给eventLoop  提交第一个任务(注册),同时会启动eventLoop ,

    eventLoop 线程会扫描执行自己任务池里面的任务,其实第一个任务就是注册(将serverChannel注册到selector上),同时也会在自己线程中开始事件循环(接受客户端的连接)。

    NioEventLoop 一直在干两件事:a.处理selector 上的 io 事件;  b.其他其他线程提交过来的task。 

    5.上面讲了bossGroup 干的事情,下面将一下workGroup 是如何工作的,其实和bossGroup 一样,因为他们公用的是同一套代码逻辑,

    不同点是每一个 SocketChannel (ServerSocketChannel.accept) 初始化时候,都会从workGroup里面选择一个 eventLoop.

    ServerBootstrapAcceptor 核心代码:

    ServerChannel channelRead 实际上是产生的一个连接,就是一个child channel ,然后从childGroup.rigister 的意思和上面serverChannel的一样,完成注册,其实也是通过提交任务实现的,只不过这里提交的是scheduledTask,这里注册挑选的child eventLoop 可能是已经启动了的(一个eventLoop负责多个child channel 的监听)

    这样就实现了bossGroup负责连接, childGroup负责连接后的具体IO读写操作, 一个ServerBootstrap 只有一个enventLoop,childGroup 需要有多个(性能方面的需要)。

    
    
    
  • 相关阅读:
    AVR单片机教程——EasyElectronics Library v1.1手册
    C++ lambda的演化
    希尔排序的正确性 (Correctness of ShellSort)
    PAT甲级满分有感
    PAT甲级题分类汇编——杂项
    Python第八章-异常
    Python第七章-面向对象高级
    Python第七章-面向对象初级
    Python第六章-函数06-高阶函数
    Python第六章-函数05-迭代器&生成器
  • 原文地址:https://www.cnblogs.com/kevin7234/p/10662449.html
Copyright © 2011-2022 走看看