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服務端啓動完成,接下來咱們看一下,一個客戶端是怎麼接入進來而且進行讀寫操做的。

相關文章
相關標籤/搜索