1. 程式人生 > >java NIO 實現非阻塞socket通訊

java NIO 實現非阻塞socket通訊

java的nio為非阻塞式socket通訊提供瞭如下幾個類:

          Selector : 它是SelectableChannel物件的多路複用器,所有希望採用非阻塞方式進行通訊的channel都應該註冊到Selector物件。可以通過呼叫此類的open()靜態方法來創Selector例項,該方法將使用系統預設的Selector來返回新的Selector。 

Selector可以同時監控多個SelectortableChannel的IO狀況,是非阻塞IO的核心。一個Selector例項有3個SelectIonKey集合

   1.所有的SelectionKey集合:代表了註冊在該Selector上的Channel,該集合可以通過keys()方法返回。

   2.被選擇的SelectionKey集合 : 代表了所有可通過select()方法獲取的,需要進行IO處理的Channel,這個集合可以通過selectedKeys()返回。

   3.被取消的SelectionKey集合:代表了所有被取消註冊關係的Channel,在下一次執行select()方法時,這些Channel對應的SelectionKey會被徹底刪除,程式通常無須直接訪問該集合。

Selector還提供了一系列和select()相關的方法。

      int select() : 監控所有註冊的Channel,當它們中間有需要處理的IO操作時,該方法返回,並將對應的Selection加入被選擇的SelectionKey集合中,該方法返回這些Channel的數量。

      int select(long timeout) : 可以設定超時時長的select()操作

      int selectNow() : 執行一個立即返回的select()操作,相對於無引數的select()方法而言,該方法不會阻塞執行緒。

      Selector wakeup() : 使一個還未返回的select()方法立刻返回

SelectableChannel類提供瞭如下方法來設定和返回該channel的模式狀態

  SelectableChannel configureBlocking(boolean block) : 設定是否採用阻塞模式

  boolean isBlocking() : 返回該channel是否是阻塞模式

  int vaildOPs() : 返回一個整數值,表示這個Channel所支援的IO操作 OP_READ(1), OP_WRITE(4),OP_CONNECT(8),OP_ACCEPT(16)

SelectableChannel還提供瞭如下幾個方法來獲取它的註冊狀態

  boolean isRegistered() : 返回該channel是否註冊在一個或多個selector上

​  SelectionKey keyFor(Selector sel) : 返回該channel和sel Selector之間的註冊關係,如果不存在註冊關係,則返回null.

就像這個圖,伺服器上的所有channel都需要向Selector註冊,Selector則負責監視這些socket的IO狀態,當其中任意一個或者多個channel具有可用的IO操作,該Selector的select()方法將會返回大於0的整數,該整數表示該Selector上有多少個channel具有可用的IO操作,並提供了selectedKeys()方法來返回這些channel對應的SelectionKey集合。正是通過Selector,使得伺服器端只需要不斷的呼叫Selector例項的select()方法,即可知道當前的所有channel是否有需要處理的IO操作。當Selector上註冊的所有channel都沒有需要處理的IO操作時,select()方法將會被阻塞,呼叫該方法的執行緒被阻塞

伺服器端的需要使用ServerSocketChannel來對客戶端進行監聽部分程式碼如下

如果需要使用非阻塞方式來處理該ServerSocketChannel,還應該設定它的非阻塞方式,並將其註冊到指定的Selector,程式碼片段如下