NIO2.0的异步套接字通道是真正的异步非阻塞I/O,它对应UXIN网络编程中的事件驱动I/O(AIO),它不需要通过多路复用器(Selector)对注册的通道进行轮询操作即可实现异步读写,从而简化了NIO的编程模型。
示例:import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousChannel; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; public class AIOServer implements Runnable{ private CountDownLatch latch; private AsynchronousServerSocketChannel asySSC; public AIOServer(){ try { asySSC = AsynchronousServerSocketChannel.open(); asySSC.bind(new InetSocketAddress(9100)); System.out.println("Server is start..."); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new Thread(new AIOServer()).start(); } @Override public void run() { latch = new CountDownLatch(1); asySSC.accept(this, new AcceptCompletionHandler()); System.out.println("Server accept()"); try { System.out.println("Server latch.await()"); latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } private class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, AIOServer>{ @Override public void completed(AsynchronousSocketChannel result, AIOServer attachment) { System.out.println("AcceptCompletionHandler completed()"); //既然已经接收到了客户端,为什么还要再次调用accept()? //原因:调用accept()方法后,如果有新的客户端连接接入,系统将回调传入的CompletionHandler实例的completed()方法, //表示新的客户端连接接入,AsynchronousServerSocketChannel可以接受成千上万个客户端 attachment.asySSC.accept(attachment,this); ByteBuffer buffer = ByteBuffer.allocate(1024); //read是异步的, //ByteBuffer dst: 接收缓冲区,用于从异步Channel中读取数据包 //A attachment:异步Channe携带的附件,通知回调的时候作为入参使用 //CompletionHandler<Integer,? super A> handler:接收通知回调的业务handler result.read(buffer,buffer,new ReadCompletionHandler(result)); } @Override public void failed(Throwable exc, AIOServer attachment) { System.out.println("AcceptCompletionHandler failed()"); exc.printStackTrace(); attachment.latch.countDown(); } } //主要用于读取半包消息和发送应答 private class ReadCompletionHandler implements CompletionHandler<Integer, ByteBuffer>{ private AsynchronousSocketChannel channel; public ReadCompletionHandler(AsynchronousSocketChannel channel){ if (this.channel == null){ this.channel = channel; } } @Override public void completed(Integer result, ByteBuffer attachment) { System.out.println("ReadCompletionHandler completed()"); attachment.flip(); byte[] body = new byte[attachment.remaining()]; attachment.get(body); String req = new String(body, StandardCharsets.UTF_8); System.out.println("Server receive :" + req); doWrite("Server ack."); } @Override public void failed(Throwable exc, ByteBuffer attachment) { System.out.println("ReadCompletionHandler failed()"); try { this.channel.close(); } catch (IOException e) { e.printStackTrace(); } } private void doWrite(String msg) { byte[] bytes = msg.getBytes(); ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length); writeBuffer.put(bytes);//将字节数组复制到缓冲区 writeBuffer.flip(); //异步write channel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { //如果没有完成发送,继续发送 if(attachment.hasRemaining()){ channel.write(attachment,attachment,this); } } @Override public void failed(Throwable exc, ByteBuffer attachment) { try { channel.close();//关闭链路,释放资源 } catch (IOException e) { e.printStackTrace(); } } }); } } }AIOClient.java
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; public class AIOClient implements CompletionHandler<Void, AIOClient>, Runnable { private AsynchronousSocketChannel clientChannel; private CountDownLatch latch; public AIOClient() { try { clientChannel = AsynchronousSocketChannel.open(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new Thread(new AIOClient()).start(); } @Override public void run() { latch = new CountDownLatch(1); //SocketAddress remote:服务器信息 //A attachment: AsynchronousSocketChannel的附件,通知回调的时候作为入参使用 //CompletionHandler<Void,? super A> handler: 异步操作回调通知接口 clientChannel.connect(new InetSocketAddress("127.0.0.1", 9100), this, this); try { latch.await();//防止异步操作没有执行完成线程就退出 } catch (InterruptedException e) { e.printStackTrace(); } try { clientChannel.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void completed(Void result, AIOClient attachment) { System.out.println("Client completed()"); byte[] req = "Client ...".getBytes(); ByteBuffer writeBuffer = ByteBuffer.allocate(req.length); writeBuffer.put(req); writeBuffer.flip(); clientChannel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { if (attachment.hasRemaining()) { clientChannel.write(writeBuffer, writeBuffer, this); } else { ByteBuffer readBuffer = ByteBuffer.allocate(1024); clientChannel.read(readBuffer, readBuffer, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { attachment.flip(); byte[] bytes = new byte[attachment.remaining()]; attachment.get(bytes); String body = new String(bytes, StandardCharsets.UTF_8); System.out.println("Client receive : " + body); latch.countDown(); } @Override public void failed(Throwable exc, ByteBuffer attachment) { try { clientChannel.close(); latch.countDown(); } catch (IOException e) { e.printStackTrace(); } } }); } } @Override public void failed(Throwable exc, ByteBuffer attachment) { try { clientChannel.close(); latch.countDown(); } catch (IOException e) { e.printStackTrace(); } } }); } @Override public void failed(Throwable exc, AIOClient attachment) { System.out.println("Client failed()"); try { clientChannel.close(); latch.countDown(); } catch (IOException e) { e.printStackTrace(); } } }运行结果:
Server is start... Server accept() Server latch.await() AcceptCompletionHandler completed() ReadCompletionHandler completed() Server receive :Client ...Client:
Client completed() Client receive : Server ack.