动态

详情 返回 返回

Netty源碼-業務流程之寫數據 - 动态 详情

Netty基本介紹,參考 Netty與網絡編程

1、源碼分析,EchoServerHandler之Write流程

1.1 write流程入口

通常我們通過ChannelRead收到消息後,需要給一個響應,通過ctx.write()將響應返回客户端。

在自定義handler的channelRead方法打一個斷點,客户端發起請求,並進入ctx.write

1.2 AbstractChannelHandlerContext#write方法

我們看到下圖中,先通過findContextOutbound方法找到下一個責任節點再執行。

如果我們自定義方法裏用的是ctx.writeAndFlush(寫入併發送數據),那麼下面就是走第一個分支,否則走第二個分支,繼續進入next.invokeWrite

1.3 invokeWrite寫入數據方法

進入了責任鏈的頭節點HeadContext的invokeWrite方法,接着進入invokeWrite0

1.4 invokeWrite0執行handler寫入方法

這裏根據handler的類型調用不同的實現類的方法,我們這裏是headContext.write方法,繼續進入

1.5 AbstractChannel.AbstractUnsafe#write方法

我們來到AbstractChannel.AbstractUnsafe#write,又是Unsafe類型,Netty的大量讀寫操作在這個類,進入最後一行的方法addMessage,該方法裏面有對寫入高水位的判斷,

然後再addMessage方法中進入incrementPendingOutboundBytes

1.6 ChannelOutboundBuffer#incrementPendingOutboundBytes高水位判斷

下圖,判斷待發送的size是不是高於高水位(默認高水位是60M),如果是,那麼unwritable設置為false。應用可以根據這個標誌決定是否繼續發送數據。

通過CAS操作,設置buffer的unwritable屬性:

1.7 應用層如何處理unwritable標誌

如圖,應用層可以通過上下文ctx獲取可以標誌,這個標誌最終是從ChannelOutboundBuffer裏獲取的

2、Flush流程

2.1 EchoServerHandler.channelReadComplete

在自定義handler的channelReadComplete方法打一個斷點,客户端發起請求,並進入ctx.flush,一直往下走,我們來到DefaultChannelPipeline.HeadContext#flush方法

2.2 進入AbstractChannel.AbstractUnsafe#flush0方法

又來到的unsafe的Flush方法,進入doWrite

2.3 NioSocketChannel#doWrite寫操作執行16次

寫數據在do-while循環中執行,默認執行16次,writeSpinCount初始是16。如果16次沒有完成,截止schedule一個新的flush task出來,而不是註冊寫事件

2.4 NioSocketChannel#doWrite的while循環

看一下doWrite的while循環

  • 最多返回1024個buffer,總數量儘量不超過maxBytesPerGatheringWrite
  • nioBufferCnt=1 ,單個bytebuffer
  • nioBufferCnt>1 ,批量數據多個bytebuffer。如果緩衝區寫滿了,註冊寫事件,啓用更多線程來處理

3.總結

寫數據首先通過Write將數據寫入Buffer(ChannelOutboundBuffer),然後通過Flush將數據發送出去。寫數據包含兩個流程Write和flush。

1、Netty寫數據太多時,超過一定水位線,會將unwritable標誌置為false,應用端根據這個標誌決定要不要發送數據

2、只要有數據,就一直寫,寫到16次,如果還沒有寫完,會重啓一個線程繼續寫

3、批量寫數據是,如果嘗試寫的都寫入了,下次會嘗試更多。

Add a new 评论

Some HTML is okay.