netty ChannelPipeline的事件傳輸機制(入站和出站的方法)

伍華鋒發表於2020-11-24


原部落格,點選這裡

一、Netty的事件型別

從ChannelPipeline的傳輸的事件型別角度,Netty的事件可以分為Inbound和Outbound事件。

Inbound事件是一個通知事件,當某件事已經發生了,然後通過Inbound事件進行通知,Inbound通常發生在Channel的狀態的改變或IO事件就緒

Outbound事件都是請求事件, 請求某件事情的發生, 然後通過Outbound事件進行通知。

1、入站事件傳播方法

1.1、ChannelHandlerContext#fireChannelRegistered()

作用:觸發事件告知Inbound ChannelHandler:ChannelHandlerContext的Channel註冊於其EventLoop,呼叫ChannelInboundHandler的channelRegistered

1.2、ChannelHandlerContext#fireChannelActive()

作用:觸發事件告知Inbound ChannelHandler:ChannelHandlerContext的Channel現在處於活動狀態,呼叫ChannelInboundHandler的channelActive

1.3、ChannelHandlerContext#fireChannelRead(Object)

作用:觸發事件告知Inbound ChannelHandler:當前Channel正在從對等方讀取訊息,呼叫ChannelInboundHandler的channelRead。

1.4、ChannelHandlerContext#fireChannelReadComplete()

作用:觸發事件告知Inbound ChannelHandler:當前讀操作讀取的最後一條訊息被channelRead(ChannelHandlerContext, Object)}使用,呼叫ChannelInboundHandler的channelReadComplete。

1.5、ChannelHandlerContext#fireExceptionCaught(Throwable)

作用:觸發事件告知Inbound ChannelHandler:丟擲Throwable異常,呼叫ChannelInboundHandler的exceptionCaught。

1.6、ChannelHandlerContext#fireUserEventTriggered(Object)

作用:觸發事件告知Inbound ChannelHandler:使用者事件正在觸發,呼叫ChannelInboundHandler的userEventTriggered。

1.7、ChannelHandlerContext#fireChannelWritabilityChanged()

作用:觸發事件告知Inbound ChannelHandler:Channel的可寫狀態發生更改,呼叫ChannelInboundHandler的channelWritabilityChanged。

1.8、ChannelHandlerContext#fireChannelInactive()

作用:觸發事件告知Inbound ChannelHandler:ChannelHandlerContext的Channel現在是不活動的,並已達到其生命週期的結束,呼叫ChannelInboundHandler的channelInactive

1.9、ChannelHandlerContext#fireChannelUnregistered()

作用:觸發事件告知Inbound ChannelHandler:ChannelHandlerContext的Channel從其EventLoop登出,呼叫ChannelInboundHandler的channelUnregistered

2、出站事件傳播方法:

2.1、ChannelHandlerContext#bind(SocketAddress, ChannelPromise)

作用:請求繫結到給定的SocketAddress,並在操作完成後通知ChannelFuture,原因可能是操作成功,也可能是錯誤,呼叫ChannelOutboundHandler的bind

2.2、ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)

作用:請求連線到給定的SocketAddress,並在操作完成後通知ChannelFuture,原因可能是操作成功,也可能是錯誤,呼叫ChannelOutboundHandler的connect

2.3、ChannelHandlerContext#write(Object, ChannelPromise)

作用:請求通過這個ChannelHandlerContext通過ChannelPipeline寫入訊息。此方法不會請求實際重新整理,因此請確保在希望請求將所有掛起資料重新整理到實際傳輸時呼叫flush()。

2.4、ChannelHandlerContext#flush()

作用:請求通過此ChannelOutboundInvoker重新整理所有掛起的訊息。

2.5、ChannelHandlerContext#read()

作用:請求從Channel讀取資料到第一個入站緩衝區,如果讀取資料,則觸發ChannelInboundHandler#channelRead(ChannelHandlerContext, Object)事件,並觸發ChannelInboundHandler#channelReadComplete(ChannelHandlerContext) channelReadComplete事件,以便處理程式可以決定繼續讀取。如果已經有一個掛起的讀操作,這個方法什麼也不做。

2.6、ChannelHandlerContext#disconnect(ChannelPromise)

作用:請求斷開與遠端對等點的連線,並在操作完成後通知ChannelFuture,原因可能是操作成功,也可能是錯誤,呼叫ChannelOutboundHandler的disconnect

2.7、ChannelHandlerContext#close(ChannelPromise)

作用:請求關閉Channel,並在操作完成後通知ChannelFuture,原因可能是操作成功,也可能是錯誤,呼叫ChannelOutboundHandler的close。關閉後,就不可能再重用它了。

2.8、ChannelHandlerContext#deregister(ChannelPromise)

作用:請求從之前分配的EventExecutor取消註冊,並在操作完成後通知ChannelFuture,原因可能是操作成功,也可能是錯誤,呼叫ChannelOutboundHandler的deregister。

3、下圖描述了在ChannelPipeline中ChannelHandlers如何處理I/O事件

這個圖是原始碼io.netty.channel.ChannelPipeline介面的備註部分提供的。
在這裡插入圖片描述

二、ChannelPipeline的結構

ChannelPipeline的資料結構是雙向連結串列。
在這裡插入圖片描述

三、HeadContext的作用

Outbound事件最後都是通過HeadContext完成(HeadContext最後呼叫NioSocketChannelUnsafe響應的方法完成),Inbound事件是從HeadContext開始。

四、TailContext的作用

一個處理位元組和訊息的特殊的捕獲全部事件的處理程式,Outbound事件是從tailContext開始,Inbound事件是在tailContext結束。

五、Inbound事件流

在Channel中呼叫DefaultChannelPipeline.fireChannelActive,接下來在Channel交給自己的DefaultChannelPipeline執行了,因為是Inbound事件,所以從HeadContext->TailContext。DefaultChannelPipeline中Inbound事件傳遞過程:

Context.fireChannelActive -> Connect.findContextInbound -> Connect.invokeChannelActive(final AbstractChannelHandlerContext next)-> next.invokeChannelActive -> nextHandler.channelActive -> nextContext.fireChannelActive

六、Outbound 事件流

6.1、Outbound事件流過程

以 Bootstrap.connect 的事件流為例,大致如下:

Bootstrap.connect -> Bootstrap.doResolveAndConnect-> Bootstrap.doResolveAndConnect0-> Bootstrap.doConnect-> AbstractChannel.connect->DefaultChannelPipeline.connect->NioSocketChannelUnsafe.connect->NioSocketChannel.doConnect->SocketChannel.connect

最後都是到了Channel,然後Channel交給自己的DefaultChannelPipeline執行,因為是 Outbound 事件,所以從TailContext ->HeadContext,HeadContext最後呼叫NioSocketChannelUnsafe響應的方法完成,事件流的NioSocketChannelUnsafe.connect->NioSocketChannel.doConnect->SocketChannel.connect部分就是在HeadContext裡面執行的。

6.2、DefaultChannelPipeline中事件傳遞過程

Context.connect -> Context.findContextOutbound -> next.invokeConnect -> handler.connect -> Context.connect

一致迴圈從TailContext 將事件傳遞到HeadContext。

相關文章