Java網路編程 -- AIO非同步網路編程

  • 2019 年 10 月 7 日
  • 筆記

AIO中的A即Asynchronous,AIO即非同步IO。它是非同步非阻塞的,客戶端的I/O請求都是由OS先完成了再通知伺服器應用去啟動執行緒進行處理,一般我們的業務處理邏輯會變成一個回調函數,等待IO操作完成後,由系統自動觸發。

在進行讀寫操作時,只需直接調用API的read/write方法即可。這兩種方法均為非同步的,對於讀操作而言,當有流可讀取時,作業系統會將可讀的流傳入read方法的緩衝區,並通知應用程式;對於寫操作而言,當作業系統將write方法傳遞的流寫入完畢時,作業系統主動通知應用程式。即可以理解為,read/write方法都是非同步的,完成後會主動調用回調函數。

AIO其實是對NIO的增強,新增了許多支援非同步的類如AsynchronousServerSocketChannel,AsynchronousChannel,AsynchronousChannelGroup,CompletionHandler等。

在Linux系統中AIO和NIO的底層實現都是epoll,epoll本身是輪詢模型,AIO只不過是對epoll又包了一層,而在windows系統中AIO是通過IOCP(完成埠)實現。而目前大多數的伺服器都是Linux系統,這也是Netty中使用NIO而非AIO的一個原因,在實際使用中由於作業系統的差異,AIO的性能有時並沒有NIO高效,因此AIO的使用並沒有很廣泛。

AIO服務端程式碼示例:

public class AIOServer {      public static void main(String[] args) throws IOException {        // 多執行緒版本      //    ExecutorService executorService = Executors.newCachedThreadPool();      //    AsynchronousChannelGroup channelGroup =      //        AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);      //      AsynchronousServerSocketChannel serverSocketChannel =      //              AsynchronousServerSocketChannel.open(channelGroup).bind(new      // InetSocketAddress(8080));        // 單執行緒版本      AsynchronousServerSocketChannel serverSocketChannel =          AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(8080));        serverSocketChannel.accept(          null,          new CompletionHandler<AsynchronousSocketChannel, Object>() {            @Override            public void completed(AsynchronousSocketChannel client, Object attachment) {              serverSocketChannel.accept(null, this);              try {                System.out.println(client.getRemoteAddress());                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);                client.read(                    byteBuffer,                    byteBuffer,                    new CompletionHandler<Integer, ByteBuffer>() {                      @Override                      public void completed(Integer result, ByteBuffer attachment) {                        attachment.flip();                        byte[] content = new byte[attachment.limit()];                        attachment.get(content);                        System.out.println(new String(content));                        try {                          System.out.println("Client: " + client.getRemoteAddress());                        } catch (IOException e) {                          e.printStackTrace();                        }                      }                        @Override                      public void failed(Throwable exc, ByteBuffer attachment) {                        System.out.println("failed: " + exc.getMessage());                      }                    });                } catch (Exception e) {                e.printStackTrace();              }            }              @Override            public void failed(Throwable exc, Object attachment) {}          });        while (true) {        try {          Thread.sleep(1000);        } catch (InterruptedException e) {          e.printStackTrace();        }      }    }  }

AIO客戶端程式碼示例:

public class AIOClient {      public static void main(String[] args) throws Exception {      AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();      socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));      Thread.sleep(1000);      ByteBuffer buffer = ByteBuffer.wrap("Hello Server".getBytes());      socketChannel.write(buffer).get();    }  }

Tags: