新聞中心
No-Block 和Block IO 的區(qū)別:

為赤城等地區(qū)用戶(hù)提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及赤城網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、赤城網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專(zhuān)業(yè)、用心的態(tài)度為用戶(hù)提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶(hù)的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
一個(gè)典型的網(wǎng)絡(luò)通訊步驟為: open (新建socket Chanel )--> connect( 嘗試建立連接) --> accept( 連接被接受) --> read( 讀取請(qǐng)求)send (輸出結(jié)果)--> close( 連接關(guān)閉) 。
對(duì)于一個(gè)No-Block 的網(wǎng)絡(luò)IO ,上面的每一步都是會(huì)馬上返回的,當(dāng)然返回的結(jié)果可能為null ,可能不為null ,這個(gè)要看下上文(context )決定。一般情況下,我們都是需要不為null 的結(jié)果,這個(gè)就需要我們?cè)谶m當(dāng)?shù)臅r(shí)機(jī),執(zhí)行適當(dāng)?shù)牟襟E,這樣就會(huì)得到我們想要的結(jié)果。何為適當(dāng)?shù)臅r(shí)機(jī)?這個(gè)下面會(huì)講。
對(duì)于一個(gè)block 的網(wǎng)絡(luò)IO ,上面的每一步執(zhí)行的時(shí)候,如果沒(méi)到適當(dāng)?shù)臅r(shí)機(jī),當(dāng)前線(xiàn)程就會(huì)被block 住,直到適當(dāng)?shù)臅r(shí)機(jī),返回給你確定的結(jié)果。
當(dāng)然對(duì)與No-Block 或者Block IO ,上面的每一步都有可能會(huì)拋出IOException 異常的。
NIO 編程接觸的幾個(gè)關(guān)鍵概念:
Buffer :是一塊連續(xù)的內(nèi)存塊,是 NIO 數(shù)據(jù)讀或?qū)懙闹修D(zhuǎn)地。Buffer 這篇blog 暫時(shí)略過(guò)不講。
Chanel :數(shù)據(jù)的源頭或者數(shù)據(jù)的目的地,用于向 buffer 提供數(shù)據(jù)或者讀取 buffer 數(shù)據(jù) ,異步 I/O 支持。
注意chanel 有2 類(lèi),一種叫SocketChanel, 一種叫ServerSocketChanel ,看名字我們就知道,一類(lèi)是普通的socket chanel ,client 端和服務(wù)器端都用的,一類(lèi)是專(zhuān)門(mén)用在server 端的。當(dāng)然這個(gè)界限也不是絕對(duì)的,互為client 和server 的情況也是存在的。
Selector : chanel 事件的偵聽(tīng)者, 它能檢測(cè)一個(gè)或多個(gè)通道 (channel) 上的事件,并將事件分發(fā)出去。使用一個(gè) select 線(xiàn)程就能監(jiān)聽(tīng)多個(gè)通道上的事件,并基于事件驅(qū)動(dòng)觸發(fā)相應(yīng)的響應(yīng)。
SelectionKey : chanel 上發(fā)生的事件, 包含了事件的狀態(tài)信息和時(shí)間以及對(duì)應(yīng)的 chanel 。
Chanel 的狀態(tài):
可連( Connectable ):當(dāng)一個(gè) Chanel 完成 socket 連接操作已完成或者已失敗放棄時(shí)。
能連( Acceptable ):當(dāng)一個(gè) Chanel 已經(jīng)準(zhǔn)備好接受一個(gè)新的 socket 連接時(shí)。
可讀( Readable ):當(dāng)一個(gè) Chanel 能被讀時(shí)。
可寫(xiě)( Writable ):當(dāng)一個(gè) Chanel 能被寫(xiě)時(shí)。
結(jié)合對(duì)照上面的網(wǎng)絡(luò)通訊步驟我們可以有以下推導(dǎo)出的結(jié)論:
當(dāng)一個(gè) Server Chanel 是 Connectable 時(shí), client 端嘗試 connect 才會(huì)成功。
當(dāng)一個(gè) Server Chanel 是 Acceptable 時(shí), client 的連接請(qǐng)求被真正受理,一個(gè)新的 chanel 會(huì)被生成,并且記錄了 localAdrress 和 remoteAddress. 為進(jìn)一步讀寫(xiě)做準(zhǔn)備。
當(dāng)一個(gè) Chanel 是 Readable 時(shí),我們從這個(gè) Chanel 中讀取數(shù)據(jù)才會(huì)成功。
當(dāng)一個(gè) Chanel 是 Writable 時(shí),我們往這個(gè) Chanel 中寫(xiě)數(shù)據(jù)才會(huì)成功。
記住一點(diǎn),對(duì)于一個(gè) No-Block 的 Chanel 來(lái)說(shuō),上面 4 個(gè)操作都會(huì)馬上返回或者拋出 IOException ,但是是不是成功就難說(shuō)了,前面就說(shuō)了,我們?cè)谝粋€(gè) Chanel 做操作的時(shí)候,我們要密切關(guān)注 Chanel 的當(dāng)前狀態(tài)。只有在知道 Chanel 的當(dāng)前狀態(tài)時(shí),我們才能在這個(gè) Chanel 上做最適當(dāng)?shù)牟僮鳌?/p>
聰明的你可能馬上就會(huì)想到,要是你操作的 Chanel 的狀態(tài)的轉(zhuǎn)換信息能被你抓取,這些問(wèn)題就迎刃而解了。對(duì)啦, NIO 就是這樣設(shè)計(jì)的。一個(gè) Chanel 可以注冊(cè)一個(gè) Selector (就像一個(gè)事件偵聽(tīng)器),而且你還要告知你想要要偵聽(tīng)的狀態(tài)。用一段代碼來(lái)說(shuō)明下:
- selector = SelectorProvider.provider().openSelector();
- serverChannel1 = ServerSocketChannel.open();
- serverChannel1.configureBlocking(false);
- InetSocketAddress isa = new InetSocketAddress("localhost", 9999);
- serverChannel1.socket().bind(isa);
- serverChannel1.register(selector, SelectionKey.OP_ACCEPT);
這段代碼的意思就是我們打開(kāi)了一個(gè) ServerChanel ,偵聽(tīng)本機(jī)的 9999 端口,并且新建了一個(gè) Selector, 然后這個(gè) ServerChanel 注冊(cè)了這個(gè) Selector ,并且指定了它感興趣的狀態(tài)類(lèi)型是 OP_ACCEPT. 這樣有什么效果呢?
注意紅色那句,這句意思是selector要求serverChannel1狀態(tài)為acceptable的時(shí)候把這個(gè)消息告訴selector。
效果就是:
當(dāng)這個(gè) ServerChanel 狀態(tài)為 Acceptable 時(shí), Selector 就會(huì)收到一個(gè)消息,這個(gè)消息當(dāng)然就是一個(gè) SelectionKey 對(duì)象。調(diào)用 Selector 的 selectedKeys ()方法,我們就能得到所有 Chanel 發(fā)送過(guò)來(lái)的消息。
因?yàn)?SelectionKey 包含 事件的狀態(tài),時(shí)間以及對(duì)應(yīng)的 Chanel ,很自然的,我們遍歷這個(gè) Set
***講講 Server 端和 Client 編程的一般步驟:
對(duì)于 Client 來(lái)一般是這樣的:
- InetSocketAddress isa = new InetSocketAddress(host, port);
- SocketChannel sc = null;
- sc = SocketChannel.open();
- sc.connect(isa);
- sc.write(data);
- …
- Sc.read(buff);
構(gòu)造一個(gè) InetSocketAddress 對(duì)象 --> open --> connect --> write --> read
注意這里用的不是 No-Block 的方式,因?yàn)?client 如果沒(méi)有得到 server 端的正確回應(yīng)的話(huà)就采取下一步操作無(wú)疑是沒(méi)有意義的。
Server 端:
- selector = SelectorProvider.provider ().openSelector();
- serverChannel = ServerSocketChannel.open ();
- serverChannel .configureBlocking( false );
- InetSocketAddress isa = new InetSocketAddress( "localhost" , 9999 );
- serverChannel .socket().bind(isa);
- serverChannel .register( selector , SelectionKey. OP_ACCEPT );
構(gòu)造一個(gè) Selector --> 打開(kāi)一個(gè) serverSocketChanel --> 設(shè)定 serverSocketChanel 為 no-block-->bind serverSocketChanel 到一個(gè) host 和 port --> register Selector 并告知感興趣的狀態(tài)類(lèi)型轉(zhuǎn)換。
在 SelectionKey Set 上遍歷操作:
- while (true) {
- selector.select();
- Iterator selectedKeys = this.selector.selectedKeys().iterator();
- while (selectedKeys.hasNext()) {
- SelectionKey key = (SelectionKey) selectedKeys.next();
- selectedKeys.remove();
- if (!key.isValid()) {
- continue;
- }
- if (key.isAcceptable()) {
- accept(key);
- } else if (key.isReadable()) {
- read(key);
- } else if (key.isWritable()) {
- write(key);
- }
- }
- }
在這個(gè)循環(huán)里面我們會(huì)根據(jù) SelectionKey 的狀態(tài),采取不同的操作的。當(dāng)連接被 accepted 時(shí), 一個(gè)新的 chanel 會(huì)被生成,并且記錄了 localAdrress 和 remoteAddress. 為進(jìn)一步讀寫(xiě)做準(zhǔn)備。
accept 函數(shù)如下:
- public void accept(SelectionKey key) throws IOException {
- ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
- SocketChanel socketChannel1 = serverSocketChannel.accept();
- socketChannel1.configureBlocking(false);
- socketChannel1.register(selector, SelectionKey.OP_READ);
- }
這里新的 Chanel 被構(gòu)建,***同樣會(huì)注冊(cè)到 selector , 同時(shí)要求當(dāng)這個(gè) Chanel 為 Readable 時(shí),一個(gè) SelectionKey 被放入到 Selector 中。這樣上面循環(huán)會(huì)用 read(key) 來(lái)處理這個(gè) SelectionKey。
原文鏈接:http://tangay.iteye.com/blog/848485
【編輯推薦】
- Java數(shù)據(jù)緩存實(shí)現(xiàn)的核心機(jī)制
- Java NIO TCP編程
- Java NIO性能測(cè)試
- Java NIO 經(jīng)典實(shí)例代碼
- Java NIO聊天窗口實(shí)例
文章題目:JavaNIO深入研究
當(dāng)前URL:http://www.dlmjj.cn/article/dhgdjhh.html


咨詢(xún)
建站咨詢(xún)
