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(); } }