1. 程式人生 > >2.2 Java 非阻塞io(NIO)

2.2 Java 非阻塞io(NIO)

Java 非阻塞io(NIO)

執行流程

在這裡插入圖片描述

1.Server

  1. 開啟通道選擇器Selector

  2. 建立ServerSocketChannel通道 並繫結介面

  3. ServerSocketChannel 通道註冊到selector serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT)並指定SelectionKey(通道型別)

  4. 呼叫selector.select()方法檢查IO就緒事件

  5. 如果就緒 1.)serverSocketChannel.accept()開始處理 在這裡插入圖片描述

2.Client

  1. SocketChannel.open()開啟channel
  2. bind繫結IP和埠
  3. 開始讀寫

程式碼展示

Server

SelectionKey.OP_READ 對應 00000001,通道中有資料可以進行讀取 SelectionKey.OP_WRITE 對應 00000100,可以往通道中寫入資料 SelectionKey.OP_CONNECT 對應 00001000,成功建立 TCP 連線 SelectionKey.OP_ACCEPT 對應 00010000,接受 TCP 連線

//            建立通道選擇器。
            Selector selector = Selector.open();
//            建立通道
            ServerSocketChannel serverSocketChannel =
ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(8081)); // 將通道註冊到selector上 // 如果為 true,則此通道將被置於阻塞模式;如果為 false,則此通道將被置於非阻塞模式 serverSocketChannel.configureBlocking(false); // 可以使用陣列組合 serverSocketChannel.
register(selector, SelectionKey.OP_ACCEPT); while (true) { // 獲取通道數目 int readyChannels = selector.select(); if(readyChannels == 0){ continue; } // 獲取SelectionKey既對通道的操作 Set<SelectionKey> readyKey = selector.selectedKeys(); // 遍歷 Iterator<SelectionKey> iterator = readyKey.iterator(); while(iterator.hasNext()){ SelectionKey key = iterator.next(); iterator.remove(); // if(key.isAcceptable()) { // // a connection was accepted by a ServerSocketChannel. // } else if (key.isConnectable()) { // // a connection was established with a remote server. // } else if (key.isReadable()) { // // a channel is ready for reading // } else if (key.isWritable()) { // // a channel is ready for writing // } if (key.isAcceptable()) { // 有已經接受的新的到服務端的連線 SocketChannel socketChannel = serverSocketChannel.accept(); // 有新的連線並不代表這個通道就有資料, // 這裡將這個新的 SocketChannel 註冊到 Selector,監聽 OP_READ 事件,等待資料 socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 有資料可讀 // 上面一個 if 分支中註冊了監聽 OP_READ 事件的 SocketChannel SocketChannel socketChannel = (SocketChannel) key.channel(); // 建立快取空間 ByteBuffer readBuffer = ByteBuffer.allocate(1024); int num = socketChannel.read(readBuffer); if (num > 0) { // 處理進來的資料... System.out.println("收到資料:" + new String(readBuffer.array()).trim()); ByteBuffer buffer = ByteBuffer.wrap("返回給客戶端的資料...".getBytes()); socketChannel.write(buffer); } else if (num == -1) { // -1 代表連線已經關閉 socketChannel.close(); } } } } }catch(IOException e){ // key.cancel(); // channel.socket().close(); // channel.close(); return; } } }

client

public class Client {

    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress("localhost",8081));
//            傳送請求
            ByteBuffer buffer = ByteBuffer.wrap("你好嗎".getBytes());
            socketChannel.write(buffer);
//            獲取server響應
            ByteBuffer readBuffer = ByteBuffer.allocate(1024);
            int num ;
            if((num = socketChannel.read(readBuffer))> 0 ){
                readBuffer.flip();
                byte[] result = new byte[num];
                readBuffer.get(result);
                String  demo = new String(result,"UTF-8");
                System.out.println("返回值:"+demo);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

結果和分析

server 在這裡插入圖片描述 client 在這裡插入圖片描述