Netty Pipeline與ChannelHandler那些事
Pipeline和ChannelHandler是Netty處理流程的重要組成部分,ChannelHandler對應一個個業務處理器,Pipeline則是負責將各個ChannelHandler串起來的“容器”,二者結合起來一起完成Netty的處理流程。
Pipeline
每個channel內部都會持有一個ChannelPipeline物件pipeline,pipeline預設實現DefaultChannelPipeline內部維護了一個DefaultChannelHandlerContext連結串列。
channel的讀寫操作都會走到DefaultChannelPipeline中,當channel完成register、active、read、readComplete等操作時,會觸發pipeline的相應方法。
- 當channel註冊到selector後,觸發pipeline的fireChannelRegistered方法;
- 當channel是可用時,觸發pipeline的fireChannelActive方法。(fireChannelActive觸發一般是在fireChannelRegistered之後觸發的);
- 當客戶端傳送資料時,觸發pipeline的fireChannelRead方法;
- 觸發pipeline的fireChannelRead方法之後會觸發pipeline的fireChannelReadComplete方法。
DefaultChannelPipeline
是Netty預設pipeline實現,對應程式碼如下:
public class DefaultChannelPipeline implements ChannelPipeline { // head和tail是handler的處理鏈/上下文 final AbstractChannelHandlerContext head; final AbstractChannelHandlerContext tail; private final Channel channel; protected DefaultChannelPipeline(Channel channel) { this.channel = ObjectUtil.checkNotNull(channel, "channel"); succeededFuture = new SucceededChannelFuture(channel, null); voidPromise = new VoidChannelPromise(channel, true); tail = new TailContext(this); head = new HeadContext(this); head.next = tail; tail.prev = head; } }
TailContext實現了ChannelOutboundHandler介面,HeadContext實現了ChannelInboundHandler和ChannelOutboundHandler介面,head和tail構成了一個連結串列。
對於Inbound操作,從head開始進行處理,向後遍歷;對於OutBound操作,從tail開始處理,向前遍歷。那麼哪些操作是Inbound哪些是OutBound操作呢?
- InBound:channelRegistered、channelActive、channelRead、channelReadComplete;
- OutBound:bind、connect、close、flush等。
注意,HeadContext實現了ChannelInboundHandler
和ChannelOutboundHandler
介面,對於OutBound操作,最後也是會走到HeadContext來處理的,其實TailContext只是一個淺封裝,實際邏輯並不多。HeadContext 中包含了一個netty底層的socket操作類,對於bind/connect/disconnect/close/deregister/beginRead/read/wirte/flush
操作都是由unsafe物件來完成的。
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler {
// netty的底層socket操作類
private final Unsafe unsafe;
HeadContext(DefaultChannelPipeline pipeline) {
super(pipeline, null, HEAD_NAME, false, true);
unsafe = pipeline.channel().unsafe();
setAddComplete();
}
// ...
}
channelPipeline的channelHandlerContext連結串列是“責任鏈”模式的體現,一個請求的處理可能會涉及到多個channelHandler,比如decodeHandler、自定義的業務channelHandler和encodeHandler。業務channelHandler示例如下:
public class EchoHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
System.out.println(in.toString(CharsetUtil.UTF_8));
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
在channelReadComplete方法中呼叫flush,其實會走到head.flush方法,最後呼叫unsafe.flush將資料傳送出去。netty pipeline就是責任鏈(或者說是流水線)模式的體現,通過pipeline機制,使netty處理資料機制具有強大的擴充套件性和靈活性。
ChannelHandler
netty的channelHandler是channel處理器,基於netty的業務處理,不管多麼複雜,都是由channelHandler來做的,可能涉及到多個channelHandler,channelHandler分為多種型別:encoder、decoder、業務處理等。
decoderHandler
decoderHandler大都是接收到資料之後進行轉換或者處理的,基本都是ByteToMessageDecoder的子類,其類圖如下:
ByteToMessageDecoder中會有一個數據暫存緩衝區,如果接收到資料不完整,可以先暫存下等到下次接收到資料時再處理。
encoderHandler
encoderHandler大都是將message轉換成bytebuf資料,基本都是MessageToByteEncoder的子類,其類圖如下:
業務channelHandler
業務處理channelHanler就是使用者自定義的業務邏輯了,一般是在最後才addLast到channel.pipeline的,比如http處理邏輯如下:
ServerBootstrap boot = new ServerBootstrap();
boot.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(8080)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast("decoder", new HttpRequestDecoder())
.addLast("encoder", new HttpResponseEncoder())
.addLast("aggregator", new HttpObjectAggregator(512 * 1024))
.addLast("handler", new HttpHandler());
}
});
DefaultChannelPipeline中的headContext(實現了ChannelOutboundHandler和ChannelInboundHandler)、tailContext(實現了ChannelOutboundHandler)和自定義的channelHandler(decoderHandler、ecoderHandler、channelHandler等,一般實現ChannelInboundHandler),通過ChannelHandlerContext的連結,組成了一個請求處理鏈。
注意,ChannelOutboundHandler和ChannelInboundHandler的順序如何新增的,其實只要記住一條:ChannelOutboundHandler之間要保證順序,ChannelInboundHandler之間要保證順序,二者之間無需保證順序。
channelHandler的執行流程圖:
TailContesxt
本身程式碼不多並且挺多方法都是"空實現",不過它的channelRead方法內部會執行ReferenceCountUtil.release(msg)
釋放msg佔用的記憶體空間,也就是說在未定義使用者ChannelHandler
或者使用者ChannelHandler的channelRead繼續傳遞後續ChannelHandler的channelRead
時,到TailContext的channelRead時會自動釋放msg所佔用記憶體。
推薦閱讀
- Netty 入門,這一篇文章就夠了
- Netty 啟動流程解析
- Netty 處理連線那些事
- Java nio 空輪詢bug到底是什麼
歡迎小夥伴關注【TopCoder】閱讀更多精彩好文。
相關推薦
Netty Pipeline與ChannelHandler那些事
Pipeline和ChannelHandler是Netty處理流程的重要組成部分,ChannelHandler對應一個個業務處理器,Pipeline則是負責將各個ChannelHandler串起來的“容器”,二者結合起來一起完成Netty的處理流程。 Pipeline 每個channel內部都會持有一個C
碼農翻身講作業系統2:程序,執行緒與作業系統那些事
我聽說我的祖先們生活在專用計算機裡, 一生只幫助人類做一件事情,比說微積分運算 了、人口統計了 、生成密碼、甚至通過織布機印花 ! 如果你想在這些專用“計算機”上乾點別的事兒,例如安裝個遊戲玩玩, 那是絕對不可能的, 除非你把它拆掉, 然後建一個全新的機器。 而我這些祖
Servlet3.0與springmvc那些事
line pat 啟動tomcat api文檔 runtime lib 功能 反射 spring 官方文檔:https://docs.spring.io/spring/docs/5.0.2.RELEASE/spring-framework-reference/web.ht
PHP基礎之與MySQL那些事
#前言 這篇文章會對PHP的MySQL擴充套件庫,MySQLI的擴充套件庫,SQL批量執行,事務控制等等進行一些簡單的講解。 #MySQL擴充套件 PHP中MySQL擴充套件,雖然因為安全的原因,在PHP5.6及往上不在支援MySQL擴充套件庫,但是還是要學習的,通過編寫案例的方式來講解。 ##案例 先說下操
Struts1與Struts2的那些事
需求 ict cin data lap 升級 otto requires exec 一、概述 Struts1以ActionServlet作為核心控制器,由ActionServlet負責攔截用戶的全部請求。Struts1框架有3個重要組成部分:Ac
mysql那些事(1)手機號與座機號碼如何存儲
varchar 兩種 body 行存儲 號碼 方式 問題 bsp 電話 創建mysql數據表的時候,經常會遇到手機號碼和座機號碼數據的存儲問題。 先說手機號碼:很多人喜歡使用數字來進行存儲,手機號不涉及到運算,並且有時候要帶括號,加號之類的字符,有時候還要以0開頭。所以,手
小於等於N的全部整數與N關於gcd(i,N)的那些事
相關 -c 因子 pos easy 介紹 直接 content tracking 相關問題1: 求小於等於N的與N互質的數的和。即∑ i (gcd(i,N)=1,
誰說顏值與實力不能並存?3.14最美女神入駐TechNeo,邀你一起聊AI與區塊鏈那些事
AI 區塊鏈 盼望著盼望著,春天來了,白色 情人節的腳步近了。轟趴派對必然少不了美女大咖駕到,她們不僅貌美如花,才華橫溢,最重要的是,在 區塊鏈、人工智能 這些熱門領域,都是響當當的行家!2018,讓我們玩兒點兒不一樣的最美女神Party,What?搞事情?Part one 女神拋出話題女神大咖會在
棋牌遊戲大咖會:人工智能與運營、安全方面的那些事
棋牌遊戲開發 流量 邏輯 extern 賬號 遊戲開發 人工智能 包括 games 本文由 網易雲 發布。 5月19日,由網易棋牌聯合網易雲以及棋牌百曉生主辦的網易棋牌遊戲大咖會在大家的熱情參與和討論下圓滿結束。 此次活動邀請了網易四川棋牌遊戲運營總監何山偉、微
小編帶你了解Netty 系列七(那些開箱即用的 ChannelHandler).
指定 ips ext 順序 偏移 ava 解決方案 sock RoCE 一、前言Netty 為許多通用協議提供了編×××和處理器,幾乎可以開箱即用, 這減少了你在那些相當繁瑣的事務上本來會花費的時間與精力。另外,這篇文章中,就不涉及 Netty 對 WebSocket協議
工作那些事(十一)談談碼農與農民工區別和發展之路 工作那些事(十二)如果哪一天,沒有了電腦 工作那些事(十三)再次失業
工作那些事系列連結快速通道,不斷更新中: 工作那些事(一)今年工作不好找 工作那些事(二)應聘時填寫個人資訊ABCD 工作那些事(三)什麼樣的公司能吸引你,什麼樣的公司適合你? 工作那些事(四)大公司VS小公司 工作那些事(五)談談專案資料整理和積累 工作那些事(六)談談
公鑰加密演算法那些事 | RSA 與 ECC 系統對比
https://blog.csdn.net/u010646653/article/details/73888734 一、背景 據記載,公元前 400 年,古希臘人發明了置換密碼。1881 年世界上的第一個電話保密專利出現。在第二次世界大戰期間,德國軍方啟用「恩尼格瑪」密碼機,密碼學在戰爭中起著非
iTutorGroup:雅思與託福,你不知道的那些事
說起雅思和託福,很多人想到的就是出國留學,但是兩者具體的區別可能還有很多的人不是特別的瞭解。很多準備留學的人都會問,出國留學靠雅思還是託福,這兩個哪個更容易些,哪個適用的國家更多呢?那就由iTutorGroup來給各位普及一下雅思和託福的相關知識,幫助出國留學的同學做個考試參考。 一、雅思
構造析構與拷貝賦值那些事
建構函式 關於建構函式,我們耳熟能詳,似乎都沒有必要成為一個知識點,或者說是重要的知識點拿出來特殊說明,畢竟C++的編譯器都能幫我們完成這個工作,只是,事情真的如想象的那麼簡單麼; 可能不是。 本文試圖挖掘關於建構函式,可能不是那麼簡單的一面,當然也不會很全面,權當一起學習了。 建構函式的概念:提供類
Native與H5互動的那些事
前言 Hybrid開發模式目前幾乎每家公司都有涉及和使用,這種開發模式兼具良好的Native使用者互動體驗的優勢與WebApp跨平臺的優勢,而這種模式,在Android中必然需要WebView作為載體來展示H5內容和進行互動,而WebView的各種安全性、相容性的問題,我想大多數人與它友誼的小床
資料結構與演算法的那些事
先佔坑,再補充。 常用演算法: (1)排序:快排、歸併排序、插入排序、希爾排序、桶排序; (2)分治演算法(divide-and-conquer),回溯演算法,貪婪演算法,動態規劃(DP); (3)二分查詢(binary search); 一、排序演算法 演
WK 與 JS 的那些事
RetainPtr<WKFrameInfo> frameInfo = wrapper(API::FrameInfo::create(frame, securityOriginData.securityOrigin())); ASSERT(isUIThread(
痞子衡嵌入式:飛思卡爾Kinetis開發板OpenSDA偵錯程式那些事(上)- 背景與架構
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是飛思卡爾Kinetis MCU開發闆闆載OpenSDA偵錯程式(上篇)。 眾所周知,嵌入式軟體開發幾乎離不開偵錯程式,因為寫一個稍有程式碼規模(5K行以上)的嵌入式應用程式一般不可能一次性搞定,沒有任何bug,出了bug並不可怕,只要我
核心是如何管理記憶體的&&頁面快取-記憶體與檔案的那些事
轉: 核心是如何管理記憶體的 原文標題:How The Kernel Manages Your Memory 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些國外高手的精彩文章翻譯一下。一來自己複習,二
資料採集與分析的那些事——從資料埋點到AB測試
作者:網易有數鄭棟。 一、為什麼企業需要一套完善的使用者行為埋點和分析平臺 產品初創期間,需要分析天使使用者的行為來改進產品,甚至從使用者行為中得到新的思路或發現來調整產品方向;產品成長過程,通過對使用者行為的多角度(多維)分析、對使用者群體的劃分以及相應行為特徵的分析和比較,來指導產品設計、運營活動,並