本文基于Netty 4
從網(wǎng)絡(luò)上接收到的數(shù)據(jù)后隔披,Netty 設(shè)計(jì)了一套Channel機(jī)制來(lái)傳遞和處理這些數(shù)據(jù)收津,這個(gè)機(jī)制包括Channel裳扯,ChannelHandler澄耍,ChannelHandlerContext和ChannelPipeline噪珊。
Channel
Channel與JDK中的Channel作用相當(dāng),是對(duì)I/O操作的封裝逾苫,比如read()卿城,write(),connect()铅搓,close()和bind()等瑟押,是Netty中非常核心的對(duì)象。我們經(jīng)常使用的NioServerSocketChannel星掰,NioSocketChannel就是其具體實(shí)現(xiàn)多望。Channel的狀態(tài)改變都會(huì)觸發(fā)相應(yīng)事件傳遞到Pipeline中,被ChannelHandler處理氢烘,下圖為Channel經(jīng)常觸發(fā)的事件
事件 | 說(shuō)明 |
---|---|
ChannelRegistered | 這里的注冊(cè)強(qiáng)調(diào)的是Channel與EventLoop是否關(guān)聯(lián)怀偷,滿(mǎn)足下列條件才能稱(chēng)為registered: 1. 將相關(guān)socket注冊(cè)到selector上;2. Channel與EventLoop關(guān)聯(lián)起來(lái) |
ChannelActive | 滿(mǎn)足下列兩個(gè)條件播玖,就是active了:1. channel 完成了注冊(cè)椎工;2. channel 綁定到了本地端口(對(duì)NioServerSocketChannel而言)或連接到了遠(yuǎn)程主機(jī)(對(duì)NioSocketChannel而言) |
ChannelHandler
ChannelHandler 是處理數(shù)據(jù)的核心對(duì)象,其對(duì)源端Channel觸發(fā)的一系列事件進(jìn)行處理。Netty提供了兩個(gè)非常重要的子接口:
- ChannelInboundHandler
- ChannelOutboundHandler
對(duì)于Inbound和Outbound的理解:
Inbound: 數(shù)據(jù)或事件由外向內(nèi)流维蒙,比如Channel注冊(cè)成功觸發(fā)的注冊(cè)事件掰吕;Channel讀好數(shù)據(jù)后的ChannelRead事件等;或者說(shuō)是與網(wǎng)絡(luò)交互完成颅痊,接下來(lái)要由Netty處理殖熟;
Outbound: 數(shù)據(jù)或事件由內(nèi)向外流,比如Netty處理好數(shù)據(jù)后要write到網(wǎng)絡(luò)斑响;去網(wǎng)絡(luò)方向read數(shù)據(jù)(read這一事件從內(nèi)向外菱属,read好數(shù)據(jù)后就是由外向內(nèi));或者說(shuō)需要與網(wǎng)絡(luò)進(jìn)行交互的操作都稱(chēng)為Outbound舰罚;
ChannelInboundHandler
ChannelInboundHandler方法如下圖所示纽门,從方法名可看出,其是對(duì)Channel觸發(fā)事件的處理营罢;
ChannelOutboundHandler
ChannelOutboundHandler的方法如下圖所示膜毁,都是與底層網(wǎng)絡(luò)交互的;其實(shí)這些方法最后都會(huì)轉(zhuǎn)調(diào)到Channel中定義的I/O方法上去愤钾,因?yàn)橹挥蠧hannel才是與網(wǎng)絡(luò)進(jìn)行交互的
ChannelHandlerContext
ChannelHandlerContext是ChannelHandler相互之間,ChannelHandler與ChannelPipeline之間交互的橋梁候醒。當(dāng)創(chuàng)建一個(gè)Channel時(shí)能颁,也會(huì)創(chuàng)建相應(yīng)的ChannelHandlerContext。ChannelHandlerContext另一個(gè)重要的作用是在Pipeline中傳播事件
ChannelPipeline
ChannelPipeline是一系列ChannelHandler的組合倒淫,與Channel相關(guān)的所有數(shù)據(jù)和事件都會(huì)流經(jīng)相應(yīng)的ChannelPipeline進(jìn)行處理伙菊。ChannelPipeline也可以觸發(fā)事件傳播,與ChannelHandlerContext觸發(fā)不同的是敌土,ChannelPipeline觸發(fā)的事件都是從第一個(gè)ChannelHandler開(kāi)始處理镜硕,而ChannelHandlerContext觸發(fā)的事件總是從下一個(gè)ChannelHandlerContext開(kāi)始處理
當(dāng)事件流在ChannelPipeline中流動(dòng)時(shí),可以調(diào)用ChannelHandlerContext或ChannelPipeline的Outbound方法改變事件的流向
在程序中返干,要手動(dòng)觸發(fā)Inbound到Outbound方向的轉(zhuǎn)變兴枯;舉個(gè)例子,比如我們定義了若干個(gè)InboundHandler矩欠,處理了用戶(hù)數(shù)據(jù)后财剖,返回給用戶(hù)一個(gè)Success,那么必須在某個(gè)InboundHandler里調(diào)用ChannelHandlerContext.write()方法讓數(shù)據(jù)流改變方向癌淮,否則躺坟,永遠(yuǎn)都無(wú)法給用戶(hù)返回;若不手動(dòng)改變方向乳蓄,輸入數(shù)據(jù)最終會(huì)走到TailContext(默認(rèn)最后一個(gè)InboundHandler)中咪橙,而這個(gè)Handler幾乎什么都沒(méi)做,那么OutBound方法永遠(yuǎn)都等不到被調(diào)用
事件流
無(wú)論是NioSocketChannel還是NioServerSocketChannel,Channel的事件都是按照下圖所示流轉(zhuǎn)