- 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方法
- 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)描述完成了
Netty如何發(fā)送消息(writeAndFlush)
最后編輯于 :
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門缘琅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人廓推,你說我怎么就攤上這事刷袍。” “怎么了樊展?”我有些...
- 文/不壞的土叔 我叫張陵呻纹,是天一觀的道長。 經(jīng)常有香客問我专缠,道長居暖,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任藤肢,我火速辦了婚禮,結果婚禮上糯景,老公的妹妹穿的比我還像新娘嘁圈。我一直安慰自己,他們只是感情好蟀淮,可當我...
- 文/花漫 我一把揭開白布最住。 她就那樣靜靜地躺著,像睡著了一般怠惶。 火紅的嫁衣襯著肌膚如雪涨缚。 梳的紋絲不亂的頭發(fā)上,一...
- 文/蒼蘭香墨 我猛地睜開眼珊燎,長吁一口氣:“原來是場噩夢啊……” “哼惭嚣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悔政,我...
- 正文 年R本政府宣布,位于F島的核電站谣辞,受9級特大地震影響迫摔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泥从,卻給世界環(huán)境...
- 文/蒙蒙 一句占、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧躯嫉,春花似錦纱烘、人聲如沸。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至帆阳,卻和暖如春哺壶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...