日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

mina 中的IoBufer(一)

發(fā)布時(shí)間:2025/6/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mina 中的IoBufer(一) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??

IoBuffer 是 MINA 中的獨(dú)有接口,主要繼承實(shí)現(xiàn)的是 java NIO 中的 ByteBuffer ,所以從使用方法上來看二者區(qū)別不大,唯一比較大的區(qū)別就是, IoBuffer 支持可變長的數(shù)據(jù)填充,對(duì)于這個(gè)類有三個(gè)關(guān)鍵屬性,分別是

capacity( 容量 ) : 是它所包含的元素的數(shù)量。緩沖區(qū)的容量不能為負(fù) limit( 限制 ) :????? 是第一個(gè)不應(yīng)該讀取或?qū)懭氲脑氐乃饕?

position ( 位置 ) :??? 是下一個(gè)要讀取或?qū)懭氲脑氐乃饕?

以上三個(gè)屬性的值都不能為負(fù),其關(guān)系遵守以下不變式:

0<= 位置 <= 限制 <= 容量

在這里還要鄭重的介紹三個(gè)方法分別是:

clear() : 使緩沖區(qū)為一系列新的通道讀取或相對(duì)放置 操作做好準(zhǔn)備:它將限制設(shè)置為容量大小,將位置設(shè)置為 0 。

flip() : 使緩沖區(qū)為一系列新的通道寫入或相對(duì)獲取 操作做好準(zhǔn)備:它將限制設(shè)置為當(dāng)前位置,然后將位置設(shè)置為 0 。

rewind() : 使緩沖區(qū)為重新讀取已包含的數(shù)據(jù)做好準(zhǔn)備:它使限制保持不變,將位置設(shè)置為 0 。

從本質(zhì)上講這三個(gè)方法都是對(duì)之前所介紹的三個(gè)屬性進(jìn)行操作,所以這里就會(huì)有一個(gè)誤區(qū),很多人從字面上解讀 clear() 這個(gè)方法,以為這個(gè)方法就是將數(shù)據(jù)擦除。而實(shí)際上 clear 方法并不有擦除數(shù)據(jù),僅僅是做了二件事,一是將 limit=capacity, 二是 position=0 ,這使得數(shù)據(jù)好像被清除,以便接收下一次的讀寫。但請(qǐng)大家千萬注意 ,在寫自定義解(編)碼器時(shí)一定不要隨便使用這些方法,請(qǐng)確保在對(duì)這些方法有了足夠的認(rèn)識(shí)后(最好的方法就是解讀源碼),才去使用它。特別是直接使用 clear() 時(shí),一旦使用不當(dāng),在截取數(shù)據(jù)非常容易發(fā)生死循環(huán)的情況,因?yàn)榍懊嬉呀?jīng)說過, clear 并不是清除數(shù)據(jù),而只是改變屬性值,也就是說原數(shù)據(jù)依舊保留,這會(huì)導(dǎo)致某些時(shí)候會(huì)不停的重置這三個(gè)屬性,去讀同一段索引的數(shù)據(jù),從而導(dǎo)致死循環(huán)。網(wǎng)上好多 demo 都是直接使用的 clear() ,其實(shí)都是存在一定隱患的,希望能看到這里的朋友能引起警惕 , 個(gè)人認(rèn)為最好的清除方式就是人為的控制 Iobuffer 的三個(gè)屬性值。 以下是參考代碼 :



int oldPos = in.position();

int oldLimit = in.limit();

....... 開始 ..........

處理數(shù)據(jù)

....... 結(jié)束 ..........

int pos = in.position();

in.limit(oldLimit);

in.position(pos);

注: 以上代碼僅適用于一次讀取不完,需要從iobuffer 中多次讀取的情況,具體情況請(qǐng)具體對(duì)待,核心思想就是操作iobuffer 的三個(gè)屬性。
sendUrgentData() 方法的使用

這個(gè)方法的作用,只要是用過 socket 編程的童鞋都知道它的作用。沒錯(cuò),它就是通過發(fā)送一個(gè)緊急字符到服務(wù)端 (對(duì) socket 來說實(shí)際上并不存在嚴(yán)格意義上的客戶端或服務(wù)端,誰主動(dòng)誰就是客戶端) ,用來測(cè)試連接是否保持的一個(gè)方法。使用這個(gè)方法有二個(gè)限制。一是必須對(duì)方的 OS 支持該方法,二是要求服務(wù)端的 SO_OOBINLINE 為 false. 否則 服務(wù) 端將會(huì)把這個(gè)緊急字符認(rèn)為是正常報(bào)文一并接收,而不是拋棄。反之當(dāng) SO_OOBINLINE 為 true 時(shí),這個(gè)緊急字符僅僅用來確認(rèn)通訊是否正常之用,服務(wù)端接收后會(huì)立刻拋棄不予處理的。默認(rèn)情況下 SO_OOBINLINE 的值就是 false, 所以一般情況下,客戶端直接用這個(gè)方法就可以測(cè)試連接是否保持了。

按理來說這個(gè)默認(rèn)設(shè)置是個(gè)好事,但在筆者的項(xiàng)目開發(fā)中曾經(jīng)因?yàn)檫@個(gè) sendUrgentData () 被困擾了近一周的時(shí)間。事情的起因要從性能測(cè)試開始說起。

測(cè)試人員在測(cè)試過程中發(fā)現(xiàn)當(dāng)前置機(jī)啟動(dòng)后有連接產(chǎn)生時(shí)就會(huì)讓 CPU 占用率高居不下,開始筆者不是很在意,認(rèn)為這個(gè)時(shí)間里有 IO 操作, CPU 高居不下很正常,后來進(jìn)一步測(cè)試發(fā)生在沒有數(shù)據(jù)發(fā)送的情況下 CPU 也會(huì)占到近 50% 左右,這個(gè)現(xiàn)象就很不正常了,于是折騰開始。

先是確認(rèn)前置機(jī)的哪個(gè)部分會(huì)占用 cpu, 很快將目標(biāo)鎖定到了調(diào)度機(jī),接下來對(duì)調(diào)度機(jī)進(jìn)行代碼排查,沒有發(fā)生任何問題,頭大了,再次進(jìn)入 QQ 群討論該問題,有人向我推薦了 JRMC (這也是我要向大家強(qiáng)烈推薦該工具的原因,網(wǎng)絡(luò)的力量是強(qiáng)大的!!!嘿嘿。。。),通過這個(gè)監(jiān)視工具,本人很快就再次縮小目標(biāo),將目標(biāo)定位到一個(gè)叫 Ioprocesse-1 的線程上面,從名字及本文之前介紹的內(nèi)容來看,很明顯這個(gè) MINA 框架內(nèi)部線程導(dǎo)致的,隨后就到網(wǎng)上查找是否有同類的現(xiàn)象,很遺憾本人可能是遇到一個(gè)前所未有的問題了,網(wǎng)絡(luò)上提到使用 MINA 導(dǎo)致 CPU 占用率過高的內(nèi)容幾乎沒有,無奈之下本人試著換 JDK 版本、 MINA 版本、甚至改寫 MINA 源代碼,一番折騰下來,結(jié)果是統(tǒng)統(tǒng)做了無用功。因?yàn)檫@個(gè)問題暫時(shí)不會(huì)影響測(cè)試和使用再加上時(shí)間過緊,后來就暫時(shí)將這個(gè)問題擱置了起來。某天,在開發(fā)的過程中筆者忽然想到:前置機(jī)的三個(gè)部分都是獨(dú)立程序,通信機(jī)的接口也都是用 mina 改寫的,為什么終端與通訊機(jī)沒有這種現(xiàn)象發(fā)生呢?一番推理之下,本人反而將目標(biāo)鎖定到了占用率正常的通機(jī)機(jī)上面了,通過反復(fù)的排查,最終將問題鎖定到了方法級(jí),那就是 sendUrgentData 這個(gè)罪魁禍?zhǔn)住?

本人試驗(yàn)發(fā)現(xiàn),只要沒有調(diào)用 sendUrgentData 方法所有一切都很正常, 但通信機(jī) 一旦調(diào)用 sendUrgentData 方法用來測(cè)試與調(diào)度機(jī)是否保持通信時(shí),就會(huì)讓調(diào)度機(jī)的 CPU 占用率瞬間飆升。但一個(gè)通信程序測(cè)試連接的方法是必不可少,而且暫時(shí)沒有更好的能代替 sendUrgentData 的方法,所以就想著去改造 sendUrgentData 的源代碼,結(jié)果一番跟蹤下來才傻了眼,原來 sendUrgentData 方法 的底層實(shí)現(xiàn)是 native 類型( 注三 )根本就無從改起,最終本人將注意打到了調(diào)度機(jī)的解碼器上面。代碼比較多筆者就不帖了,只寫上具體的解決步驟,有實(shí)際需求的,歡迎討論。

步驟:

1 、在客戶端(本例中客戶端為通訊機(jī))使用 sendUrgentData ()方法時(shí),請(qǐng)?jiān)O(shè)置一個(gè)報(bào)?? 文??? 中不可能出現(xiàn)的數(shù)字,本案例中使用的是 -16 。

2、? 在服務(wù)端的處理類(即實(shí)現(xiàn) IoHandlerAdapter 的類,為必須類)的 sessionCreated 方法內(nèi)設(shè)置 SO_OOBINLINE 為 true. 代碼如下:

@Override

public void sessionCreated(IoSession session) throws Exception {

IoSessionConfig cfg = session.getConfig();

if (cfg instanceof SocketSessionConfig) {

((SocketSessionConfig) cfg).setOobInline( true );

}

}

3、? 在服務(wù)端的解碼器中將接受到的 -16 的字符全部手動(dòng)拋棄(注意 IoBuff 三屬性的重新設(shè)定)。

至此問題解決,但從解決方法來看,這個(gè)方法并不具有代表性,當(dāng)碰到以下情況是并不一定適用:

情況一: 報(bào)文的內(nèi)容本身有可能無所不包,那么 sendUrgentData 設(shè)置什么好呢??

情況二: 客戶端的程序無法改動(dòng)時(shí),又該如何應(yīng)對(duì)呢??

當(dāng)然這個(gè)問題的終結(jié)解決方案并不在本文的討論范圍之類,這個(gè)很明顯就是 mina 的一個(gè) BUG ,不知道 2.04 的版本有沒有解決這個(gè)問題,但從官網(wǎng)所貼的問題列表來看,這個(gè) BUG 應(yīng)該是依舊存在的,奈何筆者 E 文比較爛,看看資料還可以,要我動(dòng)手寫,并將以上內(nèi)容用 E 文表達(dá)出來,確實(shí)是沒有那個(gè)勇氣的,希望能看到這一段的童鞋能代勞一、二,督促官方早日改好這個(gè) BUG ,咱也算是為開源軟件盡了一份力不是? ^_^

有的童鞋看到這里可能會(huì)說筆者是不是太啰嗦了,幾句話可以解決的事情講這么多,這里我想強(qiáng)調(diào)一下的是,本文 的核心內(nèi)容 主要講的還是使用心得, 而 不是使用方法,在這里之所以把 解決 過程講得這么詳細(xì),還是希望達(dá)成二點(diǎn)目的。

1 、筆者希望通過對(duì)過程詳細(xì)的描述,來提醒大家。做咱們這一行的不可能不遇到問題,但遇到問題首要的是先縮小范圍,再確定范圍,實(shí)際確定不下來的,不妨跟同行討論一番,如果還確定不下來,咱就暫時(shí)放一放,等腦子靜下來以后,把思路跳出來,反向追蹤,說不定問題的表象并不是問題發(fā)生的緣原呢?(這話有點(diǎn)拗口,不做解釋。。。。?? -_-!! )在本文中就是一個(gè)很明顯的例子,明明是調(diào)度機(jī)表現(xiàn)出來的 CPU 占用過高,但導(dǎo)致這一現(xiàn)象發(fā)生的卻是在通訊機(jī)上了。

2 、再次推薦 JRMC, 這東西真的很好用。獨(dú)樂樂不如眾樂樂~~?? 什么?你已經(jīng)知道了?知道了,你怎么不告訴我?你真是壞啊。。。。。。哦 ~ 漏說了一句 , 這個(gè)工具是 Oracle JRockit JDK 自帶的,據(jù)說這個(gè) JDK 的效率能比普通 JDK 的效率高上 2%-10% 非常適合在生產(chǎn)環(huán)境下使用。 什么??你還是知道了?? 你,你,你。。。。。。(吐血 ing.... )

當(dāng)然了,群眾的力量是無窮的,大家嫌我太羅嗦的話,下面的內(nèi)容我就簡單一點(diǎn)吧。



注三: 所謂的 native 類型的方法,是 JAVA 中的一種特殊方法,凡是標(biāo)注這個(gè)關(guān)鍵字的方法,其本身并沒有任何實(shí)現(xiàn)代碼,最終的運(yùn)行都是通過虛擬機(jī)調(diào)用 OS 的底層的方法來運(yùn)行的。
Concurrent 包下的一些類

這里主要推薦二個(gè)集合類,分別是 ConcurrentLinkedQueue , ConcurrentHashMap 這二個(gè)類的使用基本上不需要你考慮是不是多線程的編程,也不需要用鎖,可以大幅提高并發(fā)量過大時(shí)的對(duì)像存取,至于實(shí)現(xiàn)機(jī)制勞駕大家自己去 GOOGLE 一把吧。
結(jié)尾語

文章到這里基本上算是結(jié)束了,而項(xiàng)目最終的并發(fā)量從 2680 提升至 3.5W, 客戶要求的是 2W 的并發(fā)量,所以后面更高的并發(fā)沒有繼續(xù)再測(cè),至本文截稿為止,最新的消息是項(xiàng)目的一期工作已經(jīng)順利通過了國家級(jí)機(jī)構(gòu)的評(píng)測(cè)。但實(shí)質(zhì)上本文關(guān)于 MINA 框架還有很多東西沒有涉及到,比如說與 Spring 的結(jié)合,對(duì) Jmx 的支持,自定義協(xié)議詳細(xì)舉例等等,但我想這點(diǎn)小困難應(yīng)該不會(huì)妨礙大家對(duì) mina 的學(xué)習(xí)熱情吧!感興趣的童鞋不妨把它當(dāng)成一個(gè)課后作業(yè)來做做吧 !!? ^_^

轉(zhuǎn)載于:https://my.oschina.net/leoson/blog/104093

總結(jié)

以上是生活随笔為你收集整理的mina 中的IoBufer(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。