Netty如何發(fā)送消息(writeAndFlush)

  • 1.主要就是調(diào)用writeAndFlush怠肋,注意這邊可以調(diào)用ChannelHandlerContext的尼斧,也可以調(diào)用channel的
  • 2.上述2種方式的主要區(qū)別就是前者是從當前handler流轉(zhuǎn)到head節(jié)點你踩,而后者則送從tail節(jié)點到head
  • 3.首先還得提前申明下該方法是異步妆距,即我們方法執(zhí)行結束的時候消息很有可能還在我們的buffer里面 未通過socket發(fā)送到對端,接下來我們詳細剖析該方法偏形。
  • 4.首先調(diào)用該方法需要2個參數(shù)但指,一個是object類型的消息寡痰,還有一個ChannelPromise。如果后者我們不設置棋凳,則 默認設置一個DefaultChannelPromise拦坠,內(nèi)部持有當前的channel和loop。
  • 5.然后檢測我們的promise剩岳,為空拋出異常贞滨,是否已經(jīng)done,如果已經(jīng)done但是未取消則拋出異常拍棕,如果已經(jīng)done且取消了則直接返回true晓铆,再繼續(xù)檢測promise攜帶的channel是否與當前的channel一樣,不一樣也拋出異常绰播。還要檢測promise的class類型是否等于DefaultChannelPromise尤蒿,如果是則直接返回,否則需要進一步檢測primose是否為VoidChannelPromise或者CloseFuture幅垮,如果是可能需要拋出異常。
  • 6.當上述檢測到無效的promise的時候會直接返回尾组,并且如果我們的message是ReferenceCounted類型的則調(diào)用其release方法
    1. ReferenceCounted是netty自己維護的一個計數(shù)方式忙芒,用來管理對象的生命周期
  • 8.從當前的context尋找其前面的ChannelHandlerContext且outbound=true,outbound=true代表這個context里面的handler是ChannelOutboundHandler
  • 9.里面涉及到我們 ReferenceCounted 的touch方法,其實只是簡單方便我們deubugger讳侨,如果我們byteBuf存在泄漏我們可以debugger觀察
  • 10.netty一般使用ResourceLeakDetector來檢測bytebuf的是否泄漏(所謂的泄漏就是我們不使用該對象呵萨,但是其refCnt不為0,從而導致該bytebuf不能釋放)
  • 11.如果我們想使用ResourceLeakDetector來檢測跨跨,我們必須使用ByteBufAllocator來獲取bytebuf潮峦,而且目前只支持堆外內(nèi)存(池化和非池化)和堆內(nèi)池化,但是堆內(nèi)非池化不支持檢測勇婴。
  • 12.ResourceLeakDetector檢測的原理是我們每次使用ByteBufAllocator創(chuàng)建bytebuf會根據(jù)我們的泄漏檢測級別來進行忱嘹。如果是DISABLED則直接返回,如果是小于PARANOID級別的則我們使用隨機數(shù)來抽樣代表每次創(chuàng)建是否需要reportLeak耕渴,
  • 13.最后我們需要創(chuàng)建一個DefaultResourceLeak對象拘悦,這個對象會存放在ConcurrentMap,key就是我們的DefaultResourceLeak 其是虛引用(我們知道我們的虛引用是指當引用對象被gc橱脸,則該虛引用則會被加入一個隊列對象
    而我們所謂的泄漏是指我們的bytebuf對象被回收了但是其內(nèi)部資源對象沒有回收础米,導致即無法使用該內(nèi)存且該內(nèi)存也不會被回收進而導致內(nèi)存泄漏分苇。內(nèi)部對象存儲數(shù)據(jù)一般是數(shù)組或者directBytebuffer),而value是LeakEntry
    其只是簡單的作為一個value屁桑,同時我們還獲取我們的trackedHash=我們bytebuf的hash值医寿。
  • 14.我們的reportLeak主要就是檢測我們的logger是否可用,如果不可用我們的logger那就無法打印泄漏信息蘑斧,那么我們需要清空我們的隊列靖秩,如果logger可用則將虛引用取出來把該bytbuf的基本信息打印出來
  • 15.上面說完了內(nèi)存泄漏的問題原理,我們這邊繼續(xù)探討如何發(fā)送消息乌叶,我們在獲取到ChannelOutboundHandler后調(diào)用其invokeWriteAndFlush方法
  • 16.上面方法先調(diào)用invokeWrite0方法然后再調(diào)用invokeFlush0盆偿。
  • 17.invokeWrite0方法最終調(diào)用ChannelOutboundHandler的write方法,在這邊我們還有一個需要注意我們傳遞的消息可以是object對象准浴,但是其底層還是directBytebuffer事扭,如果我們剛開始不是傳遞這個消息對象,那么需要自己編寫一個handler進行編碼操作這個我們會在后續(xù)再細說乐横。
  • 18.最終調(diào)用到了我們的headContext的write也就是AbstractUnsafe的write方法求橄,而invokeFlush0最終調(diào)用的是AbstractUnsafe的flush方法
  • 19.write方法是首先獲取當前channel里面的ChannelOutboundBuffer,然后會判斷當前要傳遞的對象是否堆外內(nèi)存或者FileRegion則可以直接發(fā)送葡公,如果是bytebuf但是是非堆外內(nèi)存則包裝成堆外內(nèi)存罐农,如果以上都不是則直接拋出異常。
  • 20.然后我們評估下我們的要發(fā)送的內(nèi)容大小催什,包裝成Entry對象涵亏。評估大小的方式:如果是ByteBuf或者ByteBufHolder,則 直接獲取發(fā)送字節(jié)的大小蒲凶,如果是fileReginon則直接返回0气筋,其他返回unknownSize(默認是8)
  • 21.我們的entry會最終存放到entry鏈表,有三個鏈表對象:tailEntry,flushedEntry,unflushedEntry.
  • 22.我們剛開始會把第一個entry設置為tailEntry和unflushedEntry旋圆,當我們執(zhí)行addflush方法就是將unflushedEntry的鏈表的節(jié)點宠默,轉(zhuǎn)移到flushedEntry鏈表下,即flushedEntry鏈表保存的是即將要發(fā)送的entry節(jié)點灵巧,而我們每次調(diào)用addMessge都是將entry對象添加到當前tailEntry的下一個搀矫。
  • 23.flush的時候會觀察是否存在FlushPending,即看當前的selectionKey是否有效以及當前的channel是否注冊了write事件刻肄。當key有效且注冊了write事件則代表當前的channel已經(jīng)寫滿了需要等channel有空閑瓤球,我們需要等待我們write事件觸發(fā)了再真正調(diào)用flush(寫事件的就緒的本質(zhì)是只要channel不為空閑就會觸發(fā)寫事件)
  • 24.首先需要判斷inFlush0,如果為true則代表當前flush方法正在調(diào)用則直接返回肄方,然后判斷調(diào)用NioSocketChannel的doWrite方法
  • 25.該write方法首先獲取writeSpinCount冰垄,即單個消息最多循環(huán)發(fā)送的次數(shù),然后將我們的bytebuf組裝ByteBuffer的數(shù)組,目前默認最大的是1024虹茶,數(shù)組的所有數(shù)據(jù)最大值不大于maxBytesPerGatheringWrite逝薪,當然不一定不超過,只是盡量不超過蝴罪。然后每次發(fā)送的時候檢測發(fā)送的字節(jié)大小如果等于0代表channel滿了董济,滿了就注冊寫事件等到channel有buffer可寫數(shù)據(jù)即可
  • 26.如果成功一次性寫完則嘗試取消寫事件并設置一個直接調(diào)用寫事件的任務這樣就算我們在此期間沒有任何事件發(fā)生,我們還可以繼續(xù)去將channelOutboundbuffer里面的entry寫出去了要门。
  • 27至此整個寫事件都已經(jīng)描述完成了
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末虏肾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子欢搜,更是在濱河造成了極大的恐慌封豪,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炒瘟,死亡現(xiàn)場離奇詭異吹埠,居然都是意外死亡,警方通過查閱死者的電腦和手機疮装,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門缘琅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人廓推,你說我怎么就攤上這事刷袍。” “怎么了樊展?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵呻纹,是天一觀的道長。 經(jīng)常有香客問我专缠,道長居暖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任藤肢,我火速辦了婚禮,結果婚禮上糯景,老公的妹妹穿的比我還像新娘嘁圈。我一直安慰自己,他們只是感情好蟀淮,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布最住。 她就那樣靜靜地躺著,像睡著了一般怠惶。 火紅的嫁衣襯著肌膚如雪涨缚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天策治,我揣著相機與錄音脓魏,去河邊找鬼兰吟。 笑死,一個胖子當著我的面吹牛茂翔,可吹牛的內(nèi)容都是我干的混蔼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼珊燎,長吁一口氣:“原來是場噩夢啊……” “哼惭嚣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悔政,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤晚吞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谋国,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體槽地,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年烹卒,在試婚紗的時候發(fā)現(xiàn)自己被綠了闷盔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡旅急,死狀恐怖逢勾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情藐吮,我是刑警寧澤溺拱,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站谣辞,受9級特大地震影響迫摔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泥从,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一句占、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧躯嫉,春花似錦纱烘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至帆阳,卻和暖如春哺壶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工山宾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留至扰,地道東北人。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓塌碌,卻偏偏與公主長得像渊胸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子台妆,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355