檔案IO用到的FileChannel并不支援非阻塞操作,NIO用得更多的是在網絡IO中,NIO中的網絡通道是非阻塞IO的實作,基于事件驅動,非常适用于伺服器需要位置大量連接配接,但是資料交換量不大的情況。
在Java中編寫Socket伺服器,通常有以下幾種模式:
一個用戶端連接配接用一個線程,優點:程式編寫簡單;缺點:如果連接配接非常多,配置設定的線程也會非常多,伺服器可能會因為資源耗盡而崩潰。
把每一個用戶端連接配接交個一個擁有固定數量線程的連接配接池,優點:程式編寫相對簡單,可以處理大量的連接配接。缺點:線程的開銷非常大,連接配接如果非常多,排隊現象比較嚴重。
使用NIO,用費阻塞的IO方式處理。這種模式可以用一個線程,處理大量的用戶端連接配接。
1、Selector(選擇器),能夠檢測多個注冊的通道上是否有時間發生,如果有事件發生,便擷取事件然後針對每個事件進行相應的處理。這樣就可以隻用一個單線程去管理多個通道,也就是管理多個連接配接。這樣使得隻有在連接配接真正有讀寫事件發生時,才會調用函數來進行讀寫,就大大地減少了系統開銷,并且不必為每個連接配接都建立一個線程,不用維護多個線程,并且避免了多線程之間的上下文切換導緻的開銷。
該類的常用的方法如下所示
public static Selector open() 得到一個選擇器對象
public int select(long timeout) 健康所有注冊的通道,當其中有IO操作可以進行時,對應的SelectionKey加入到内部稽核中并傳回,參數用來設定逾時時間
public Set<SelectionKey> selectedKeys() 從内部稽核中得到所有的SelectionKey
2、SelectionKey,代表了Selector和網絡通道的注冊關系,一共四種:
- int OP_ACCEPT 有新的網絡連接配接可以accept,值為16
- int OP_CONNECT 代表連接配接已經建立,值為8
- int OP_READ和OP_WRITE 代表了讀、寫操作,值為1和4
該類常用方法如下:
- public abstract Selector selector(),得到與之關聯的Selector 對象
- public abstract SelectableChannel channel(),得到與之關聯的通道
- public final Object attachment(),得到與之關聯的共享資料
- public abstract SelectionKey interestOps(int ops),設定或改變監聽事件
- public final boolean isAcceptable(),是否可以accept
- public final boolean isReadable(),是否可以讀
- public final boolean isWritable(),是否可以寫
3、ServerSocketChannel,用來在伺服器端監聽新的用戶端Socket 連接配接
常用方法如下所示:
- public static ServerSocketChannel open(),得到一個ServerSocketChannel 通道
- public final ServerSocketChannel bind(SocketAddress local),設定伺服器端端口号
- public final SelectableChannel configureBlocking(boolean block),設定阻塞或非阻塞模式,取值false 表示采用非阻塞模式
- public SocketChannel accept(),接受一個連接配接,傳回代表這個連接配接的通道對象
- public final SelectionKey register(Selector sel, int ops),注冊一個選擇器并設定監聽事件
4、SocketChannel,網絡IO 通道,具體負責進行讀寫操作
常用方法如下所示:
- public static SocketChannel open(),得到一個SocketChannel 通道
- public final SelectableChannel configureBlocking(boolean block),設定阻塞或非阻塞模式,取值false 表示采用非阻塞模式
- public boolean connect(SocketAddress remote),連接配接伺服器
- public boolean finishConnect(),如果上面的方法連接配接失敗,接下來就要通過該方法完成連接配接操作
- public int write(ByteBuffer src),往通道裡寫資料
- public int read(ByteBuffer dst),從通道裡讀資料
- public final SelectionKey register(Selector sel, int ops, Object att),注冊一個選擇器并設定監聽事件,最後一個參數可以設定共享資料
- public final void close(),關閉通道