java nio(reactor, selector, selectionKey)


SocketChannel vs. ServerSocketChannel

  • 父類:SelectableChannel。Channel表現了一個可以進行IO操作的通道(比如,通過FileChannel,我們可以對文件進行讀寫操作)
  • ServerSocketChannel主要用在Server中,用於接收客戶端的鏈接請求
    SocketChannel則用於真正的讀寫數據,同時還可以用於客戶端發送鏈接請求。
  • 真正實現讀寫數據操作的就是這些SocketChannel,上面的ServerSocketChannel只是負責接收連接請求。
  • 以下均簡稱為channel

 

 

channel vs. Selector

  • channel需要注冊到selector上。channel可以注冊到一個或多個Selector上以進行異步IO操作。

       channel.register(selector, SelectionKey.OP_ACCEPT);

       channel.register(selector, xxx, object); //attachment被存放在返回的SelectionKey中

       channel.keyFor(selector); //返回該channe在Selector上的注冊關系所對應的SelectionKey。若無注冊關系,返回null。

  • Selector可以同時監控多個SelectableChannel的IO狀況,是異步IO的核心。

       Selector.open(); //靜態方法,創建一個selector實例

       selector.select(); //selector通過調用select(),將注冊的channel中有事件發生的取出來進行處理。監控所有注冊的channel,當其中有注冊的IO操作可以進行時,該函數返回,並將對應的SelectionKey加入selected-key set。

       selector.keys(); //所有注冊在這個Selector上的channel

       selector.selectedKeys(); //所有通過select()方法監測到可以進行IO操作的channel

 

SelectionKey

  • 代表了Selector和SelectableChannel的注冊關系

       key.attachment(); //返回SelectionKey的attachment,attachment可以在注冊channel的時候指定。

       key.channel(); // 返回該SelectionKey對應的channel。

       key.selector(); // 返回該SelectionKey對應的Selector。

       key.interestOps(); //返回代表需要Selector監控的IO操作的bit mask

       key.readyOps(); //返回一個bit mask,代表在相應channel上可以進行的IO操作。

 

 

Demo1: Server端底層如何接受連接

   int n = selector.select();                                   // 得到selector所捕獲的事件數量
   if( n > 0 ){                                                        // 當真正捕獲到事件時,才執行相應操作
    Set selectedKeys = selector.selectedKeys();  // 獲取捕獲到的事件集合
Iterator i = selectedKeys.iterator();
while(i.hasNext())              
{
SelectionKey s = (SelectionKey) i.next(); // 對事件一一處理

//一個key被處理完成后,就都被從就緒關鍵字(ready keys)列表中除去
i.remove();
if(s.isAcceptable())                                   // 表示該事件為OP_ACCEPT事件
{
// 從channel()中取得我們剛剛注冊的ServerSocketChannel。
// 為請求獲取新的SocketChannel
SocketChannel sc = ((ServerSocketChannel)s.channel()).accept().socket().getChannel(); 

sc.configureBlocking(false);                 // 設置SocketChannel為非阻塞方式
sc.register(selector, SelectionKey.OP_READ |SelectionKey.OP_WRITE); 
                       // 將新的SocketChannel注冊到selector中,注冊事件為OP_READ和OP_WRITE
}
else
{
// 執行其他操作
}
  }
   }

 

Demo2: Server端底層如何讀取channel上的數據

                SelectionKey s = (SelectionKey) i.next();                          // 對事件一一處理

//一個key被處理完成后,就都被從就緒關鍵字(ready keys)列表中除去
i.remove();
                 ByteBuffer clientBuffer = ByteBuffer.allocate(4096);
if (key.isReadable()) {                                                               // 讀信息
                     SocketChannel channel = (SocketChannel) key.channel();    // 獲取相應的SocketChannel
                     int count = channel.read(clientBuffer);                                   // 將數據讀入clientBuffer
                     if (count > 0) {                                                                       // 當有數據讀入時
                         clientBuffer.flip();                                                               // 反轉此緩沖區
                         CharBuffer charBuffer = decoder.decode(clientBuffer);     // 如果需要,對緩沖區中的字符進行解碼
                          ...                                                                                     // 處理數據
                     }
                 }

 

Demo3: Client端底層如何發起連接、寫入數據

   InetSocketAddress addr = new InetSocketAddress(host,port);
   //生成一個socketchannel
   sc = SocketChannel.open();        
   //連接到server
   sc.connect(addr);                       // 連接到server

   if(sc.finishConnect()){                // 當連接成功時,執行相應操作
    ByteBuffer buffer = .....             // 准備數據
    buffer.filp();                              // 反轉此緩沖區
    while(w_buff.hasRemaining())  // 發送數據到server
          sc.write(w_buff);

 

學習文檔:

http://www.iteye.com/topic/40489

http://blog.csdn.net/derekjiang/article/details/4465697

http://blog.csdn.net/derekjiang/article/details/4470175

http://www.cnblogs.com/freedom-elf/archive/2011/08/11/2135015.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM