Java NIO (四) 選擇器(Selector)


選擇器(Selector) 是 SelectableChannle 對象的多路復用器,Selector 可以同時監控多個 SelectableChannel 的 IO 狀況,也就是說,利用 Selector可使一個單獨的線程管理多個 Channel,selector 是非阻塞 IO 的核心。

SelectableChannle 的繼承樹如下圖:

選擇器(Selector)的應用:

當通道使用register(Selector sel, int ops)方法將通道注冊選擇器時,選擇器對通道事件進行監聽,通過第二個參數指定監聽的事件類型。

其中可監聽的事件類型包括以下:

  讀 : SelectionKey.OP_READ (1)

  寫 : SelectionKey.OP_WRITE (4)

  連接 : SelectionKey.OP_CONNECT (8)

  接收 : SelectionKey.OP_ACCEPT (16)

如果需要監聽多個事件是:

  int key = SelectionKey.OP_READ | SelectionKey.OP_WRITE ; //表示同時監聽讀寫操作

如何應用請看代碼:

public class NIOBlocking2 {

   //客戶端 @Test
public void client() throws Exception { //1. 獲取socketChannel SocketChannel sChannel = SocketChannel.open(); //2. 創建連接 sChannel.connect(new InetSocketAddress("127.0.0.1", 9898)); ByteBuffer buf = ByteBuffer.allocate(1024); //3. 設置通道為非阻塞 sChannel.configureBlocking(false); @SuppressWarnings("resource") Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { String msg = scanner.nextLine(); buf.put((new Date() + ":" + msg).getBytes()); buf.flip(); //4. 向通道寫數據 sChannel.write(buf); buf.clear(); } }
   //服務端 @Test
public void server() throws Exception { //1. 獲取服務端通道 ServerSocketChannel ssChannel = ServerSocketChannel.open(); ssChannel.bind(new InetSocketAddress(9898)); //2. 設置為非阻塞模式 ssChannel.configureBlocking(false); //3. 打開一個監聽器 Selector selector = Selector.open(); //4. 向監聽器注冊接收事件 ssChannel.register(selector, SelectionKey.OP_ACCEPT); while (selector.select() > 0) { //5. 獲取監聽器上所有的監聽事件值 Iterator<SelectionKey> it = selector.selectedKeys().iterator(); //6. 如果有值 while (it.hasNext()) { //7. 取到SelectionKey SelectionKey key = it.next(); //8. 根據key值判斷對應的事件 if (key.isAcceptable()) { //9. 接入處理 SocketChannel socketChannel = ssChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { //10. 可讀事件處理 SocketChannel channel = (SocketChannel) key.channel(); readMsg(channel); } //11. 移除當前key it.remove(); } } } private void readMsg(SocketChannel channel) throws IOException { ByteBuffer buf = ByteBuffer.allocate(1024); int len = 0; while ((len = channel.read(buf)) > 0) { buf.flip(); byte[] bytes = new byte[1024]; buf.get(bytes, 0, len); System.out.println(new String(bytes, 0, len)); } } }

NIO的非阻塞性:

nio的非阻塞是對於網絡通道來說的,需要使用Channel.configureBlocking(false)來設置通道為非阻塞的,如果沒設置,默認是阻塞的。


免責聲明!

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



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