zoukankan      html  css  js  c++  java
  • Netty源码分析--Channel注册&绑定端口(下)(七)

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

          

          就是 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() 方法。

          

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

            然后循环执行这个任务, 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服务端启动完成,接下来我们看一下,一个客户端是怎么接入进来并且进行读写操作的。

  • 相关阅读:
    ssh图示+hibernate图示
    spring Transactional
    Spring datasource
    sqlloader导入数据
    Spring Aop Annotation(@Pointcut)
    ajax传输文件+检验
    Spring Aop Annotation
    JDK的动态代理
    nginx代理gitlab
    python相关
  • 原文地址:https://www.cnblogs.com/huxipeng/p/11075097.html
Copyright © 2011-2022 走看看