NIO原理剖析與Netty初步----淺談高效能伺服器開發(一)

來源:互聯網
上載者:User

標籤:channel   src   有意思   bytes   多個   table   logs   stack   list   

    除特別註明外,本站所有文章均為原創,轉載請註明地址 

    在博主不長的工作經曆中,NIO用的並不多,由於使用原生的Java NIO編程的複雜性,大多數時候我們會選擇Netty,mina等開源架構,但理解NIO的原理就不重要了嗎?恰恰相反,理解NIO底層機制是理解這一切的基礎,由此我總結一下當初學習NIO時的筆記,以便後續複習。

     以下是我理解的Java原生NIO開發大致流程:

    

       大致描述的是服務端的NIO操作。

第一步,綁定一個服務的連接埠

       這與傳統阻塞IO中的ServerSocket類似,沒什麼好說的

第二步,開啟通道管理器Selector並在Selector上註冊一個事件

      當註冊的事件發生時,Selector.select()會返回,否則一直阻塞。這一步很有意思,也是NIO第一個與傳統IO不同的地方,NIO通過一個Selector線程可以管理大量用戶端串連,反之傳統IO一個用戶端串連進來必須建立一個新的線程為它服務(當然你可以使用串連池),我們知道線程對服務端來說是十分寶貴的資源,一個服務端進程所包含的線程是有   限的;此外,每個線程會佔用一定的記憶體空間,過多的線程可能導致記憶體溢出,這種情況下你可能會到想對虛擬機器進行調優,比如通過修改參數-Xss限制單個線程大小,但這又可   能導致StackOverFlow;另外,線程調度需要切換上下文,對於作業系統,它需要通過TCB(線程式控制制塊)來對線程進行調度,過多的環境切換浪費了CPU時間,降低了系統效     率。

第三步,輪循訪問Selector,當註冊的事件到達時,方法返回

   下面的代碼可以看到,方法整體是一個死迴圈,輪詢訪問Selector,發生某些已經註冊在Selector上的事件時,該方法返回。可以通過selector.selectedKeys擷取發生的事件,

該方法返回的是一個泛型集合Set<SelectionKey>,遍曆這個集合與遍曆普通集合沒有什麼不同,這裡我們通過迭代器迭代的原因是我們需要刪除已經處理的Key,避免重複處理:

public void listen() throws IOException {// 輪詢訪問selector        while (true) {            // 當註冊的事件到達時,方法返回;否則,該方法會一直阻塞            selector.select();            // 獲得selector中選中的項的迭代器,選中的項為註冊的事件            Iterator<?> ite = this.selector.selectedKeys().iterator();            while (ite.hasNext()) {                SelectionKey key = (SelectionKey) ite.next();                //刪除已選的key,以防重複處理                ite.remove();         //這裡可以寫我們自己的處理邏輯                handle(key);            }        }}

   在第二步時,已經在Selector上註冊了Accept事件,當這裡的selector.select()返回時,代表用戶端已經可以串連了,在handle方法裡可以處理這個事件:

public void handle(SelectionKey key) throws IOException {    // 用戶端請求串連事件    if (key.isAcceptable()){
//從Key裡可以很方便的取到註冊這個事件的Channel

        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        // 獲得和用戶端串連的通道
        SocketChannel channel = server.accept();
        // 設定成非阻塞
        channel.configureBlocking(false);

        logger.info("用戶端已經串連!");

        //用戶端串連在通道管理器Selector上註冊讀事件

        channel.register(this.selector, SelectionKey.OP_READ);

    }}

    上面的代碼很簡單,我們通過key擷取到註冊它的那個Channel,在這裡是ServerSocketChannel,通過server.accept()擷取用戶端串連,這裡同樣可以類比到傳統的阻塞

IO,在阻塞IO中我們可以通過ServerSocket.accept擷取到socket,唯一不同的是,阻塞IO中的accept方法是阻塞操作,而NIO中是非阻塞的。

    當然,僅僅是串連到用戶端並沒有什麼用處,服務端需要有讀寫資料的能力,比如你可以用NIO實現一個Http伺服器(當然最佳實務使用Netty等架構)。所以我們需要在Selector

上註冊讀事件,同樣,當讀事件發生時,執行我們自己的商務邏輯。下面是修改後的代碼:

public void handle(SelectionKey key) throws IOException {    if (key.isAcceptable()){        ServerSocketChannel server = (ServerSocketChannel) key.channel();        SocketChannel channel = server.accept();        channel.configureBlocking(false);        logger.info("用戶端已經串連!");        channel.register(this.selector, SelectionKey.OP_READ);    } else if(key.isReadable()){        SocketChannel channel = (SocketChannel) key.channel();        // 建立讀取緩衝        ByteBuffer buffer = ByteBuffer.allocate(1024);        //讀取到Buffer中        int read = channel.read(buffer);        if(read > 0){            byte[] data = buffer.array();            String msg = new String(data).trim();            logger.info("receive msg: {}",msg)                        //回寫資料            ByteBuffer outBuffer = ByteBuffer.wrap("OK".getBytes());            channel.write(outBuffer);        }else{            logger.info("client closed!!!");            key.cancel();        }    }} 
總結

     本文大致講述了使用NIO進行伺服器端開發的大致流程,但代碼顯然仍然存在問題,其一是我們只使用了一個線程執行所有操作,包括接收用戶端串連,讀取資料,返回資料,對於這個簡單的Demo來說已經足夠了,但在實際的伺服器開發中,例如你想使用NIO開發自己的HTTP伺服器,伺服器本地需要做大量操作,包括解析使用者請求,根據請求路由到某一個Action執行商務邏輯,這其中又很可能某些資料從資料庫讀取,渲染模板等操作,十分耗時,這無疑又稱為系統的瓶頸,再者,使用單一線程不能充分利用多核CPU提供的計算能力。下一篇中會看到,在基於Reactor模型的Netty中,會使用一個Boss線程接收用戶端請求,使用多個Worker線程執行具體的商務邏輯。

    

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

     

 

     

   

NIO原理剖析與Netty初步----淺談高效能伺服器開發(一)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.