Netty源码分析--Channel注册&绑定端口(下)(七)

      接下来,我们看到的就是两个非常重要的方法

      Netty源码分析--Channel注册&绑定端口(下)(七)_第1张图片

      就是 processSelectedKeys() 和  runAllTasks() 方法了。

      selectionKey中ready的事件,如accept、connect、read、write等,由processSelectedKeys方法触发。属于I/O任务。

      添加到taskQueue中的任务,如register0、bind0等任务,由runAllTasks方法触发。属于非I/O任务。

      两种任务的执行时间比由变量ioRatio控制,默认为50,则表示允许非IO任务执行的时间与IO任务的执行时间相等。

      我们看一下 processSelectedKeys() 方法, 因为 selectedKeys != null 所以进入  processSelectedKeysOptimized() 方法。

      由于没有这里只是启动服务端,没有客户端接入进来,所以我们先跳过processSelectedKeys(),一会我们结合客户端接入来讲这里。

      直接看 runAllTasks() 方法。

      Netty源码分析--Channel注册&绑定端口(下)(七)_第2张图片

        Runnable task = pollTask(); 这个就是从 taskQueue 中拿出一个task。

        然后循环执行这个任务, safeExecute(task)。

        Netty源码分析--Channel注册&绑定端口(下)(七)_第3张图片

       这个方法也是很简单,就是直接执行Runnable接口中的run()方法(这里并不是启动一个线程,而是仅仅的执行一个普通的run方法)。

       大家想一下这里的这个task应该是什么呢?

        Netty源码分析--Channel注册&绑定端口(下)(七)_第4张图片

        大家还记得这段代码吗? 就是这个 register0() 方法。

        Netty源码分析--Channel注册&绑定端口(下)(七)_第5张图片

         我们先进入到 doRegister() 方法

         Netty源码分析--Channel注册&绑定端口(下)(七)_第6张图片

         继续传入当前的eventloop中的selector, opt = 0,  第三个参数 this 就是当前的 NioServerSocketChannel。 进入register 方法

        Netty源码分析--Channel注册&绑定端口(下)(七)_第7张图片

           大家看我圈出来的这一句,熟悉吗?我当时将NIO的时候是不是讲到了。

           这里就是把当前的channel注册到这个多路复用器上。并且把 NioServerSocketChannel 传进去当做附件 attach, 注册的 interestOps = 0 

          好了,当执行完task,由于是一个死循环,那么会继续执行刚刚的整个过程。

          Netty源码分析--Channel注册&绑定端口(下)(七)_第8张图片

           好了,总结一下: 也就是说有一个线程一直在这里不断循环的等待新的 selectionKey中ready的事件,如accept、connect、read、write等。 如果有待处理的task,将会去优先处理的task.

           一会我们会启动一个客户端看一下是怎么交互的。

           整个注册完成之后,接下来就是 绑定端口 ,将服务对外开放出去。

           我们看下AbstractBootstrap中的  doBind() 方法。

            Netty源码分析--Channel注册&绑定端口(下)(七)_第9张图片

              由于整个注册过程是异步的,所以这里 regFuture.isDone() 是否已经完成,如果完成直接执行doBind0(),如果没有完成,那么就监听异步响应方法,等待成功之后,再执行doBind0()方法。

             我们进入doBind0()方法

             Netty源码分析--Channel注册&绑定端口(下)(七)_第10张图片

           我们看其实就是向eventLoop中的任务队列中添加一个task。

           这里我们debug来看一下

          另外在 AbstractBootstrap中打一个断点,在这里等待注册事件先完成。

          Netty源码分析--Channel注册&绑定端口(下)(七)_第11张图片

         好的,我们启动服务端。

         Netty源码分析--Channel注册&绑定端口(下)(七)_第12张图片

        断点进来了, 我们再在  NioEventLoop 中打一个断点,因为这里是处理task的地方

           Netty源码分析--Channel注册&绑定端口(下)(七)_第13张图片

           我们发现有一个主线程,一个子线程,如下图

          Netty源码分析--Channel注册&绑定端口(下)(七)_第14张图片

         切换到子线程,我们看下 task 的执行过程。

         Netty源码分析--Channel注册&绑定端口(下)(七)_第15张图片

       因为switch中的hasTask() 是true,那么我们就直接看

       Netty源码分析--Channel注册&绑定端口(下)(七)_第16张图片

       Netty源码分析--Channel注册&绑定端口(下)(七)_第17张图片

     从任务队列中取出一个task,我们看到就是刚刚我们的那个任务。然后通过safeExecute(task)执行run方法

      Netty源码分析--Channel注册&绑定端口(下)(七)_第18张图片

      继续F5。我们看进入到了runnable中的run方法。

   Netty源码分析--Channel注册&绑定端口(下)(七)_第19张图片

     接下来就是一段链式调用,链式访问pipleline中的handler         TailContext -> ServerBootstrapAcceptor -> LoggingHandler -> HeadContext

     Netty源码分析--Channel注册&绑定端口(下)(七)_第20张图片

     TailContext 和 ServerBootstrapAcceptor 中没有bind方法,直接进入LoggingHandler的bind方法,打一个日志

    Netty源码分析--Channel注册&绑定端口(下)(七)_第21张图片

   继续f5进入到 HeadContext中的bind方法

  Netty源码分析--Channel注册&绑定端口(下)(七)_第22张图片

  Netty源码分析--Channel注册&绑定端口(下)(七)_第23张图片

   先判断是否激活,如果没有,则稍后链式调用handlers中的 channelActive()方法。

   进入doBind方法

   Netty源码分析--Channel注册&绑定端口(下)(七)_第24张图片

   ok,到这里绑定端口成功。

  目前为止,Server服务端启动完成,接下来我们看一下,一个客户端是怎么接入进来并且进行读写操作的。

你可能感兴趣的:(Netty源码分析--Channel注册&绑定端口(下)(七))