Netty源碼分析-- 處理客戶端接入請求(八) Netty源碼分析--建立Channel(三)

           這一節咱們來一塊兒看下,一個客戶端接入進來是什麼狀況。首先咱們根據以前的分析,先啓動服務端,而後打一個斷點。html

    這個斷點打在哪裏呢?就是NioEventLoop上的select方法上。socket

    

   而後咱們啓動一個客戶端。工具

   

  而後咱們debug看到,selectedKey的數量 = 1,說明有accept或者讀寫等事件發生。oop

  接下就會進 processSelectedKeys() 源碼分析

咱們上一節講到,這裏的attach就是NioServerSocketChannel, 咱們進入 processSelectedKey() 方法post

     重點來了,這裏對各類事件進行分發,debug看咱們如今是16,也就是說是accept事件。url

     繼續跟進去F5進去spa

     

    發現進入到了AbstractNioMessageChannel的read方法。這裏進入的是 AbstractNioMessageChannel !!!;debug

    爲了加深印象,咱們先暫停,從新跑一個讀事件3d

   

  發現當前的selectKey = 1,也就是讀事件

 

 F5 進入

 

  發現,讀事件進入到AbstractNioByteChannel中,

  那麼也就是accept進入  AbstractNioMessageChannel , 而 read 進入AbstractNioByteChannel 中。

  好了,咱們回過頭來繼續看 AbstractNioMessageChannel 中的read 方法。

  

 關於這個分配器,這裏我先不看,待後面分析內存模型的時候再說。咱們直接看下面的代碼:

 

 咱們發現這個是一個循環,不斷的調用doReadMessages方法,而且傳入了一個readBuf,並且這個readBuf是一個ArrayList, 那這裏咱們猜想多是把讀取到的客戶端放到List集合中保存,而後再循環處理客戶端鏈接。

 進入doReadMessage方法一探究竟。

經過工具類調用 NioServerSocketChannel 內部封裝的 serverSocketChannel 的 accept 方法,獲取一個SocketChannel, 若是你們還記得我第一篇講NIO的地方 Netty源碼分析--NIO(一),這裏應該會有印象,我這裏貼出來:

 這裏就是獲取到了客戶端的socketChannel

 

 而後這裏將SocketChannel封裝成了一個NioSocketChannel,而後添加到了readBuf這個ArrayList中存儲。

 

封裝這裏,這裏不想多說了,跟建立NioServerSocketChannel相似,你們能夠去回顧一下 Netty源碼分析--建立Channel(三)。 

 

 繼續往下看,這裏就是循環readBuf,鏈式執行 管道中的 handler 的 ChannelRead 方法。

 根據前面幾篇的分析,咱們知道 , pipeline 裏面又 4 個 handler ,分別是 Head,LoggingHandler,ServerBootstrapAcceptor,Tail,鏈式調用其中的 ChannelRead  方法,這裏咱們着重看  ServerBootstrapAcceptor 中個的 ChannelRead  方法。

 這裏爲剛剛的客戶端channel 添加了handler,設置了options和childAttrs,注意這裏的addLast方法,並無調用initChannel方法,具體這裏添加了什麼,我前面幾篇有說起,你們能夠再回顧一下。

  

   接下來這裏呢,就是把客戶端channel註冊到多路複用器上,跟服務端channel註冊的流程是同樣的。你們能夠去看

   Netty源碼分析--Channel註冊(上)(五)

   Netty源碼分析--Channel註冊(中)(六)

   Netty源碼分析--Channel註冊&綁定端口(下)(七)

  咱們直接說重點:

   

   註冊完成以後,就進入到了 pipeline.invokeHandlerAddedIfNeeded() 方法,咱們跟下這個代碼。

   

   跟下去咱們會進入上圖這個execute()方法,如上圖,咱們看下  ctx

   那麼鏈式結構也就是 HeadContext -> NettyServer【ChannelInitializer】(個人啓動類) -> TailContext

   

  不斷的跟下去,咱們發現其實就是去調用當初咱們在NettyServer中的initChannel。

  

  那麼也就是說,這裏纔是真正往pipeline中添加handler的過程!!!

  神奇的是,後面還有一個remove方法。

  

  那麼這個是啥意思呢?咱們再來看下ctx的鏈式結構

   

   

  也就是說變成了 HeadContext - > NettyServer ->  IdleStateHandler ...等 -> TailContext

  你們發現了嗎? NettyServer 還在, 也就是  ChannelInitializer 這個handler 還在鏈上,可是它的做用已經結束了,沒錯,這裏刪除的就是它。

  

  怎麼刪的就不說了,無非就是把 ChannelInitializer 兩段的鏈表直接鏈接起來,把 ChannelInitializer  剔除就能夠了。

  接下來就是  pipeline.fireChannelRegistered(); 和 pipeline.fireChannelActive();

  就是在全部的handler中鏈式調用channelRegister 和 channelActive方法。

  總結一下:ServerBootstrapAcceptor 纔是那個負責接收客戶端鏈接,而且將其註冊到多路複用器上的核心類

  那麼到這裏,客戶端的接入就完成了,下一篇咱們來看,客戶端的讀寫過程以及Netty的內存模型是什麼樣子的。

相關文章
相關標籤/搜索