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

      接下来,咱们看到的就是两个很是重要的方法异步

      

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

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

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

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

      咱们看一下 processSelectedKeys() 方法, 由于 selectedKeys != null 因此进入  processSelectedKeysOptimized() 方法。3d

      因为没有这里只是启动服务端,没有客户端接入进来,因此咱们先跳过processSelectedKeys(),一会咱们结合客户端接入来说这里。rest

      直接看 runAllTasks() 方法。日志

      

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

        而后循环执行这个任务, safeExecute(task)。接口

        

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

       你们想一下这里的这个task应该是什么呢?

        

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

       

         咱们先进入到 doRegister() 方法

         

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

        

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

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

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

         

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

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

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

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

            

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

             咱们进入doBind0()方法

             

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

           这里咱们debug来看一下

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

          

         好的,咱们启动服务端。

         

        断点进来了, 咱们再在  NioEventLoop 中打一个断点,由于这里是处理task的地方

           

           咱们发现有一个主线程,一个子线程,以下图

          

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

         

       由于switch中的hasTask() 是true,那么咱们就直接看

       

       

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

      

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

   

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

     

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

    

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

  

  

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

   进入doBind方法

   

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

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

相关文章
相关标签/搜索