今天小編給大家分享一下Java NIO的知識點有哪些的相關(guān)知識點,內(nèi)容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
站在用戶的角度思考問題,與客戶深入溝通,找到泉港網(wǎng)站設(shè)計與泉港網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設(shè)計與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:成都網(wǎng)站設(shè)計、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、域名申請、虛擬空間、企業(yè)郵箱。業(yè)務(wù)覆蓋泉港地區(qū)。
No-Block 和Block IO 的區(qū)別:
一個典型的網(wǎng)絡(luò)通訊步驟為: open (新建socket Chanel )--> connect( 嘗試建立連接) --> accept( 連接被接受) --> read( 讀取請求)send (輸出結(jié)果)--> close( 連接關(guān)閉) 。
對于一個No-Block 的網(wǎng)絡(luò)IO ,上面的每一步都是會馬上返回的,當(dāng)然返回的結(jié)果可能為null ,可能不為null ,這個要看下上文(context )決定。一般情況下,我們都是需要不為null 的結(jié)果,這個就需要我們在適當(dāng)?shù)臅r機,執(zhí)行適當(dāng)?shù)牟襟E,這樣就會得到我們想要的結(jié)果。何為適當(dāng)?shù)臅r機?這個下面會講。
對于一個block 的網(wǎng)絡(luò)IO ,上面的每一步執(zhí)行的時候,如果沒到適當(dāng)?shù)臅r機,當(dāng)前線程就會被block 住,直到適當(dāng)?shù)臅r機,返回給你確定的結(jié)果。
當(dāng)然對與No-Block 或者Block IO ,上面的每一步都有可能會拋出IOException 異常的。
NIO 編程接觸的幾個關(guān)鍵概念:
Buffer :是一塊連續(xù)的內(nèi)存塊,是 NIO 數(shù)據(jù)讀或?qū)懙闹修D(zhuǎn)地。Buffer 這篇blog 暫時略過不講。
Chanel :數(shù)據(jù)的源頭或者數(shù)據(jù)的目的地,用于向 buffer 提供數(shù)據(jù)或者讀取 buffer 數(shù)據(jù) ,異步 I/O 支持。
注意chanel 有2 類,一種叫SocketChanel, 一種叫ServerSocketChanel ,看名字我們就知道,一類是普通的socket chanel ,client 端和服務(wù)器端都用的,一類是專門用在server 端的。當(dāng)然這個界限也不是絕對的,互為client 和server 的情況也是存在的。
Selector : chanel 事件的偵聽者, 它能檢測一個或多個通道 (channel) 上的事件,并將事件分發(fā)出去。使用一個 select 線程就能監(jiān)聽多個通道上的事件,并基于事件驅(qū)動觸發(fā)相應(yīng)的響應(yīng)。
SelectionKey : chanel 上發(fā)生的事件, 包含了事件的狀態(tài)信息和時間以及對應(yīng)的 chanel 。
Chanel 的狀態(tài):
可連( Connectable ):當(dāng)一個 Chanel 完成 socket 連接操作已完成或者已失敗放棄時。
能連( Acceptable ):當(dāng)一個 Chanel 已經(jīng)準(zhǔn)備好接受一個新的 socket 連接時。
可讀( Readable ):當(dāng)一個 Chanel 能被讀時。
可寫( Writable ):當(dāng)一個 Chanel 能被寫時。
結(jié)合對照上面的網(wǎng)絡(luò)通訊步驟我們可以有以下推導(dǎo)出的結(jié)論:
當(dāng)一個 Server Chanel 是 Connectable 時, client 端嘗試 connect 才會成功。
當(dāng)一個 Server Chanel 是 Acceptable 時, client 的連接請求被真正受理,一個新的 chanel 會被生成,并且記錄了 localAdrress 和 remoteAddress. 為進一步讀寫做準(zhǔn)備。
當(dāng)一個 Chanel 是 Readable 時,我們從這個 Chanel 中讀取數(shù)據(jù)才會成功。
當(dāng)一個 Chanel 是 Writable 時,我們往這個 Chanel 中寫數(shù)據(jù)才會成功。
記住一點,對于一個 No-Block 的 Chanel 來說,上面 4 個操作都會馬上返回或者拋出 IOException ,但是是不是成功就難說了,前面就說了,我們在一個 Chanel 做操作的時候,我們要密切關(guān)注 Chanel 的當(dāng)前狀態(tài)。只有在知道 Chanel 的當(dāng)前狀態(tài)時,我們才能在這個 Chanel 上做最適當(dāng)?shù)牟僮鳌?/p>
聰明的你可能馬上就會想到,要是你操作的 Chanel 的狀態(tài)的轉(zhuǎn)換信息能被你抓取,這些問題就迎刃而解了。對啦, NIO 就是這樣設(shè)計的。一個 Chanel 可以注冊一個 Selector (就像一個事件偵聽器),而且你還要告知你想要要偵聽的狀態(tài)。用一段代碼來說明下:
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);
這段代碼的意思就是我們打開了一個 ServerChanel ,偵聽本機的 9999 端口,并且新建了一個 Selector, 然后這個 ServerChanel 注冊了這個 Selector ,并且指定了它感興趣的狀態(tài)類型是 OP_ACCEPT. 這樣有什么效果呢?
注意紅色那句,這句意思是selector要求serverChannel1狀態(tài)為acceptable的時候把這個消息告訴selector。
效果就是:
當(dāng)這個 ServerChanel 狀態(tài)為 Acceptable 時, Selector 就會收到一個消息,這個消息當(dāng)然就是一個 SelectionKey 對象。調(diào)用 Selector 的 selectedKeys ()方法,我們就能得到所有 Chanel 發(fā)送過來的消息。
因為 SelectionKey 包含 事件的狀態(tài),時間以及對應(yīng)的 Chanel ,很自然的,我們遍歷這個 Set
***講講 Server 端和 Client 編程的一般步驟:
對于 Client 來一般是這樣的:
InetSocketAddress isa = new InetSocketAddress(host, port); SocketChannel sc = null; sc = SocketChannel.open(); sc.connect(isa); sc.write(data); … Sc.read(buff);
構(gòu)造一個 InetSocketAddress 對象 --> open --> connect --> write --> read
注意這里用的不是 No-Block 的方式,因為 client 如果沒有得到 server 端的正確回應(yīng)的話就采取下一步操作無疑是沒有意義的。
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)造一個 Selector --> 打開一個 serverSocketChanel --> 設(shè)定 serverSocketChanel 為 no-block-->bind serverSocketChanel 到一個 host 和 port --> register Selector 并告知感興趣的狀態(tà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); } } }
在這個循環(huán)里面我們會根據(jù) SelectionKey 的狀態(tài),采取不同的操作的。當(dāng)連接被 accepted 時, 一個新的 chanel 會被生成,并且記錄了 localAdrress 和 remoteAddress. 為進一步讀寫做準(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)建,***同樣會注冊到 selector , 同時要求當(dāng)這個 Chanel 為 Readable 時,一個 SelectionKey 被放入到 Selector 中。這樣上面循環(huán)會用 read(key) 來處理這個 SelectionKey。
以上就是“Java NIO的知識點有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。