NIO SelectionKey事件理解

在Java NIO編程中,我們可以在通道上注冊(cè)OP_ACCEPTOP_CONNECT,OP_READ,OP_WRITE,下面我們分別看下各種事件在源碼中的注釋說(shuō)明:

  • OP_ACCEPT

Operation-set bit for socket-accept operations. Suppose that a selection key's interest set contains OP_ACCEPT at the start of a selection operatio. If the selector detects that the corresponding server-socket channel is ready to accept another connection, or has an error pending, then it will add OP_ACCEPT to the key's ready set and add the key to its selected-key set.

表明一個(gè)SelectionKey包含Accept事件,當(dāng)selector檢測(cè)到關(guān)聯(lián)的server-socket channel準(zhǔn)備好接受一個(gè)連接或者發(fā)生錯(cuò)誤時(shí),會(huì)將該事件加入到該key的'ready set'中,并將該key加入到selected-key set中。

  • OP_CONNECT

Operation-set bit for socket-connect operations. Suppose that a selection key's interest set contains OP_CONNECT at the start of a selection operation. If the selector detects that the corresponding socket channel is ready to complete its connection sequence, or has an error pending, then it will add OP_CONNECT to he key's ready set and add the key to its selected-key set.

當(dāng)一個(gè)socket channel已經(jīng)準(zhǔn)備好完成連接操作或者發(fā)生錯(cuò)誤時(shí)會(huì)將該事件加入到該key的'ready set'中,并將該key加入到selected-key set中。

  • OP_READ

Operation-set bit for read operations. Suppose that a selection key's interest set contains OP_READ at the start of a selection operation. If the selector detects that the corresponding channel is ready for reading, has reached end-of-stream, has been remotely shut down for further reading, or has an error pending, then it will add OP_READ to the key's ready-operation set and add the key to its selected-key set.

當(dāng)一個(gè)channel準(zhǔn)備好可以被讀取(比如socket已經(jīng)讀到了新的字節(jié),其讀取緩沖區(qū)有尚未被應(yīng)用讀取的數(shù)據(jù),可通知應(yīng)用程序從讀取緩沖區(qū)進(jìn)行讀?。?、已經(jīng)到達(dá)數(shù)據(jù)流的結(jié)尾、遠(yuǎn)程另一端已經(jīng)關(guān)閉或者發(fā)生錯(cuò)誤時(shí),會(huì)將該事件加入到該key的'ready set'中,并將該key加入到selected-key set中。

  • OP_WRITE

Operation-set bit for write operations. Suppose that a selection key's interest set contains OP_WRITE at the start of a selection operation. If the selector detects that the corresponding channel is ready for writing, has been remotely shut down for further writing, or has an error pending, then it will add OP_WRITE to the key's ready set and add the key to its selected-key set.

當(dāng)一個(gè)channel 準(zhǔn)備好進(jìn)行寫(xiě)入操作(比如原先socket寫(xiě)入緩沖已滿(mǎn),現(xiàn)在已經(jīng)發(fā)送了部分?jǐn)?shù)據(jù),寫(xiě)入緩沖騰出了一些空間,會(huì)通知應(yīng)用程序進(jìn)行寫(xiě)入)、遠(yuǎn)程另一端已經(jīng)關(guān)閉或者發(fā)生錯(cuò)誤時(shí),會(huì)將該事件加入到該key的'ready set'中,并將該key加入到selected-key set中。

通過(guò)上面的注釋?zhuān)覀兛梢灾雷?cè)事件只是告訴selector在檢測(cè)到各種事件準(zhǔn)備好可以執(zhí)行時(shí)告訴應(yīng)用,應(yīng)用可以執(zhí)行相應(yīng)的事件,但是注冊(cè)感興趣的事件并不是必須的,沒(méi)有注冊(cè)事件依然可以進(jìn)行讀取、寫(xiě)入操作,比如讀取操作,如果不注冊(cè)OP_READ事件,應(yīng)用程序依然可以隨時(shí)嘗試從channel中讀取數(shù)據(jù),但是并不能保證讀取成功,因?yàn)榭赡?code>socket讀取緩沖區(qū)中可能并不存在數(shù)據(jù)。但是如果注冊(cè)了OP_READ事件,在selector檢測(cè)到該事件準(zhǔn)備好了再去讀取,則可以最大程度上的保證可以讀到數(shù)據(jù)。寫(xiě)入也是一樣的道理,不注冊(cè)OP_WRITE應(yīng)用程序也可以隨時(shí)進(jìn)行寫(xiě)入,但是可能因?yàn)榫彌_區(qū)滿(mǎn)而寫(xiě)入失敗,如果注冊(cè)了OP_WRITE事件,在selector檢測(cè)到該事件時(shí)再進(jìn)行寫(xiě)入,可以最大程度上保證寫(xiě)入成功。所以說(shuō)注冊(cè)相關(guān)事件不是必須的,注冊(cè)了事件可以由selector檢測(cè)到事件準(zhǔn)備好可以執(zhí)行了再執(zhí)行相關(guān)的事件,避免了許多無(wú)效的嘗試。

下面我們可以看下Selector.select方法的源碼注釋?zhuān)?/p>

Selects a set of keys whose corresponding channels are ready for I/O operations. This method performs a blocking selection operation. It returns only after at least one channel is selected, this selector's wakeup method is invoked, or the current thread is interrupted, whichever comes first.

當(dāng)注冊(cè)在該Selector上的某個(gè)Channel的至少一個(gè)事件準(zhǔn)備好之后才會(huì)返回。因?yàn)樽x取事件是一個(gè)被動(dòng)的事件,應(yīng)用程序一般會(huì)等待讀取數(shù)據(jù),所在我們一般會(huì)注冊(cè)讀取事件,在Channel準(zhǔn)備好讀取之后告訴應(yīng)用程序進(jìn)行讀取。而寫(xiě)事件屬于一種主動(dòng)的事件,我們一般不會(huì)注冊(cè)寫(xiě)事件,有要寫(xiě)的數(shù)據(jù)則直接寫(xiě)數(shù)據(jù)至Channel即可,寫(xiě)入失敗則表示Channel暫時(shí)沒(méi)有準(zhǔn)備好被寫(xiě)入,此時(shí)應(yīng)用可以向Channel注冊(cè)寫(xiě)事件,讓Channel在準(zhǔn)備好接收寫(xiě)事件時(shí)告訴應(yīng)用,但是一旦應(yīng)用寫(xiě)完所有的數(shù)據(jù),則一般會(huì)取消注冊(cè)的寫(xiě)事件,因?yàn)槿绻麛?shù)據(jù)寫(xiě)完了,但是沒(méi)有取消注冊(cè)的寫(xiě)事件,Selector.select方法可能會(huì)經(jīng)常因?yàn)橛袑?xiě)事件準(zhǔn)備完畢而返回,但是應(yīng)用卻無(wú)數(shù)據(jù)需要寫(xiě)。

關(guān)于寫(xiě)事件的注冊(cè)與取消注冊(cè),大家可以看下Netty向網(wǎng)絡(luò)中寫(xiě)數(shù)據(jù)的實(shí)現(xiàn),正常情況下不會(huì)注冊(cè)寫(xiě)事件,只是在發(fā)生寫(xiě)方法返回0,或者寫(xiě)半包的情況下,也即Channel沒(méi)有準(zhǔn)備好寫(xiě)入或者寫(xiě)緩沖已滿(mǎn),但是應(yīng)用還有數(shù)據(jù)需要寫(xiě)的情況下才注冊(cè)寫(xiě)事件,讓Channel在準(zhǔn)備好寫(xiě)入時(shí)及時(shí)通知應(yīng)用,然后應(yīng)用可以繼續(xù)寫(xiě),寫(xiě)完之后會(huì)及時(shí)取消對(duì)寫(xiě)事件的注冊(cè)。后面會(huì)有專(zhuān)文介紹Netty Write原理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容