JDK1.7升级了NIO类库,升级后的NIO类库被称为NIO2.0,引人注目的是,Java正式提供了异步文件I/O操作,同时提供了与UNIX网络编程事件驱动I/O对应的AIO。
NIO2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。异步通道提供两种方式获取操作结果。
- 通过java.util.concurrent.Future类来表示异步操作的结果;
- 在执行异步操作的时候传入一个java.nio.channels。
NIO2.0的异步套接字通道是真正的异步非阻塞I/O,它对应UXIN网络编程中的事件驱动I/O(AIO),它不需要通过多路复用器(Selector)对注册的通道进行轮询操作即可实现异步读写,从而简化了NIO的编程模型。
示例:AIOServer.java
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.javaimport 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:
Server is start...
Server accept()
Server latch.await()
AcceptCompletionHandler completed()
ReadCompletionHandler completed()
Server receive :Client ...
Client:Client completed()
Client receive : Server ack.