Nio Server實現

項目GitHub地址:https://github.com/scientist272/non-blocking-server

nio 與阻塞式io

nio即non-blocking io,在網絡編程中,相對於傳統的阻塞式io,nio只需要一個或者幾個線程就能處理大量併發的socket請求,而傳統的阻塞式io處理大量併發請求時,很多時候需要爲每一個請求創建一條新線程,對於很多長時間保持socket連接但是不發送數據的請求,爲它們申請大量線程會造成資源浪費。

傳統阻塞式io:

在這裏插入圖片描述
服務器持續調用accept方法接收socket連接,如果當前沒有連接,則一直阻塞到有請求connect到服務器爲止。但是這種io會有問題,如圖中,當一個請求連接到服務器後,如果它一直什麼事都不做,服務器需要等待它的write方法發送數據,這時候會造成處理線程的阻塞,服務器無法處理其他socket的連接請求。
解決方法:爲每一個socket請求創建一條處理線程
但是這種方法還是有很大的缺點:即之前提到的,如果有很多請求一直保持和服務器的連接,但卻不做任何事,會造成大量的服務器資源浪費。

nio(非阻塞式io)

nio的解決思路:
服務器保持一個或幾個線程,通過selector(選擇器)來處理大量併發請求。
在這裏插入圖片描述
開啓一個serverSocketChannel,將它註冊到selector中,操作爲SelectionKey.OP_ACCEPT,即監聽接收就緒的socket(有socket連接服務器時,selector就會知道,之後可對它們就行讀就緒註冊,寫就緒註冊等)。調用selector的selectNow()方法,這是一個非阻塞的native方法,它會選擇出當前所有可操作的socketChannel,包括acceptable,readable,writeable等,即接收就緒,讀就緒,寫就緒的通道。
簡而言之,就是服務器在一個線程中循環調用selectNow()方法,當有socket請求連接服務器時,就對它就行註冊,註冊完之後就做其他事去了,比如處理其他之前註冊的socket請求發送的數據,等這個新連接的socket有數據時,纔對它進行處理。

實現思路

服務器用兩個線程來工作,一個線程負責接收新的socket,然後將它們加入到一個工作隊列中,另一個負責處理socket的線程從工作隊列中獲取socket並對它們進行註冊。
在這裏插入圖片描述
處理線程會對每一個註冊的socket創建一個messageReader實例來讀取它們的數據並解析,一個messageWriter負責服務器向它們返回數據。整個處理流程如下圖所示
在這裏插入圖片描述
對請求的數據存儲用了一個可變的緩衝區數據結構,其中的byte數組用於存儲數據,循環隊列用於記錄byte數組可用的數據塊。
具體實現見GitHub代碼,有詳細註釋。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章