selector的應用
② 非阻塞nio的demo (基於serversocketchannel)
③ 非阻塞nio的demo (基於datagramchannel)
前文【1.1】nio 和 bio 對比分析,引出 nio 介紹了他們的區別,該篇介紹
如何使用nio進行網路通訊.
nio中,執行緒通常將非阻塞 io 的空閒時間用於在其他管道上執行 io 操作,所以單獨的執行緒可以管理多個輸入和輸出通道。
public
class
blockingnio
//因為此時伺服器不知道客戶端是否已經傳送完畢,故服務端一直在處於 read(),造成阻塞
schannel.
shutdownoutput()
;//4. 接受伺服器的響應訊息
int len =0;
while
((len = schannel.
read
(buf))!=
-1)//5. 關閉通道 try catch finally
inchannel.
close()
; schannel.
close()
;}@test
//服務端
public
void
server()
throws ioexception
//6. 傳送反饋給客戶端
buf.
put(
"服務端接收資料成功"
.getbytes()
);buf.
flip()
; schannel.
write
(buf)
;//把緩衝區的資料寫入到accept()得到的客戶端管道
//7. 關閉通道
schannel.
close()
; outchannel.
close()
; sschannel.
close();}}
客戶端流程:
1. 客戶端獲取通道 (繫結遠端伺服器 ip、port),獲取檔案管道,並建立緩衝區
2. 讀取本地檔案到繫結指定檔案的輸入管道,並將緩衝區資料寫入到客戶端管道
服務端流程:
1. 獲取伺服器通道和繫結最終生成檔案管道。
2. 服務端管道繫結客戶端的連線 (指定客戶端的埠)
3. 分配緩衝區
4. 接收客戶端的資料,並儲存到本地(緩衝區)
非阻塞 io 的核心 —> 選擇器 (selector) 是 selectablechannle 物件的多路復用器,selector允許單執行緒處理多個 channel。如果你的應用開啟了多個連線(通道),但每個連線的流量都很低,使用selector就會很方便。
selector selector = selector.
open()
;
channel.
configureblocking
(false);
selectionkey selectionkey = channel.
register
(selector, selectionkey.op_read)
;
監聽的事件狀態選擇與組合可以用「位或」操作符將常量連線起來
int interestset = selectionkey.op_read | selectionkey.op_write;
注: 與selector一起使用時,channel必須處於非阻塞模式下。這意味著不能將filechannel與selector一起使用,因為filechannel不能切換到非阻塞模式。而套接字通道都可以。
當向selector註冊channel時,register()方法會返回乙個selectionkey物件。這個物件代表了註冊到該selector的通道,也包含了一些你感興趣的屬性:
如果你對「讀就緒」的通道感興趣,select()方法會返回讀事件已經就緒的那些通道。 方法
描述int select()
返回的 int 值表示自上次呼叫select()方法後就緒的通道數
(不懂:阻塞到至少有乙個通道在你註冊的事件上就緒了)
select(long timeout)
和select()一樣,除了最長會阻塞timeout毫秒(引數)。
selectnow()
不會阻塞,不管什麼通道就緒都立刻返回
(譯者注:此方法執行非阻塞的選擇操作。
如果自從前一次選擇操作後,沒有通道變成可選擇的,
則此方法直接返回零)
selectionkey物件代表了註冊到該selector的通道。可以通過selector的selectedkeyset()方法訪問這些sk物件。
set selectedkeys = selector.
selectedkeys()
;iterator keyiterator = selectedkeys.
iterator()
;while
(keyiterator.
hasnext()
)else
if(key.
isconnectable()
)else
if(key.
isreadable()
)else
if(key.
iswritable()
) keyiterator.
remove()
;}
該迴圈遍歷已選擇鍵集中的每個鍵,並檢測各個鍵所對應的通道的就緒事件。
selector不會自己從已選擇鍵集中移除selectionkey例項。必須在處理完通道時自己移除。下次該通道變成就緒時,selector會再次將其放入已選擇鍵集中。
selector.wakeup()方法可以使呼叫select()方法的執行緒從阻塞狀態返回。
如果有其它執行緒呼叫了wakeup()方法,但當前沒有執行緒阻塞在select()方法上,下個呼叫select()方法的執行緒會立即"醒來 (wake up)"。
用完selector後呼叫其close()方法會關閉該selector,且使註冊到該selector上的所有selectionkey例項無效。通道本身並不會關閉。
經過上面的channel分析,我們對①的**做出改進:
客戶端
@test
public
void
client()
throws ioexception schannel.
close()
;//5. 關閉通道
}
服務端
@test
public
void
server()
throws ioexception
else
if(sk.
isreadable()
)}//if
keyiterator.
remove()
;//15. 取消選擇鍵 selectionkey
}//while
}//while
}
selectionkey.channel()方法返回的通道需要轉型成你要處理的型別,如serversocketchannel或socketchannel等。
public
class
testnonblockingnio2
dc.close()
;}@test
public
void
receive()
throws ioexception
} it.
remove()
;}}}
selectablechannle 的結構如下圖:
NIO 的非阻塞式網路通訊
若註冊時不止監聽乙個事件,則可以使用 位或 操作符連線。方 法描 述int interestops 獲取感興趣事件集合 int readyops 獲取通道已經準備就緒的操作的集合 selectablechannel channel 獲取註冊通道 selector selector 返回選擇器 boo...
NIO的非阻塞式網路通訊
虛擬記憶體被作業系統劃分成兩塊 核心空間和使用者空間,核心空間是核心 執行的地方,使用者空間是使用者程式 執行的地方。當程序執行在核心空間時就處於核心態,當程序執行在使用者空間時就處於使用者態。服務端會判斷核心位址空間有沒有資料,如果沒有資料的話,此時的服務端就處於等待狀態。後來,我們想到使用多執行...
C 網路通訊
c 網路通訊 一 伺服器端程式 10.17 1.建立伺服器端socket 1 使用socket類 建立伺服器socket物件 socket objs new socket 引數 使用ipendpoint類設定伺服器ip位址和埠號 或使用dns類 ipaddress serip ipaddress.p...