Java4中开始的NIO虽然提供了非阻塞的IO方法,但是IO操作还是同步的,即业务线程必须等到IO操作准备好再进行其他操作。
在 Java 7 中又引入了 NIO 的改进版 NIO 2.0,NIO 2.0 的异步套接字通道是真正的异步非阻塞I/O,它对应UNIX网络编程中的事件驱动I/O(AIO),它不需要通过多路复用器(Selector)对注册的通道进行轮询操作即可实现异步读写,从而简化了NIO的编程模型。
我们再将之前的请求时间的demo再通过AIO进行重写:
服务端主程序入口:
package com.servertest;
import java.io.IOException;
public class TimeServerTest {
public static void main(String[] args) throws IOException {
int port = 8888;
AsyncTimeServerHandler timeServer = new AsyncTimeServerHandler(port);
// 通过一个独立的I/O线程创建异步时间服务器客户端handler,在实际的项目中,不需要独立的线程
new Thread(timeServer, "AIO-AsyncTirneServerHandler-O0l").start();
}
}
用来接收客户端连接的AsyncTimeServerHandler类:
package com.servertest;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.CountDownLatch;
public class AsyncTimeServerHandler implements Runnable {
private int port;
CountDownLatch latch;
AsynchronousServerSocketChannel asynchronousServerSocketChannel;
public AsyncTimeServerHandler(int port) {
// TODO Auto-generated constructor stub
this.port = port;
try {
// 创建异步服务端通道
asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open();
// 绑定监听端口
asynchronousServerSocketChannel.bind(new InetSocketAddress(port));
System.out.println("The time server is start in port: " + port);
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
latch = new CountDownLatch(1);
// 接受客户端连接
doAccept();
try {
latch.await();//让线程在此阻塞,防止服务端执行完毕退出
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public void doAccept() {
// AcceptCompletionHandler对象用于接收accept操作成功的通知消息
asynchronousServerSocketChannel.accept(this, new AcceptCompletionHandler());
}
}
再创建一个AcceptCompletionHandler类来接收新的客户端连接:
package com.servertest;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, AsyncTimeServerHandler>{
@Override
public void completed(AsynchronousSocketChannel result, AsyncTimeServerHandler attachment) {
// 每当接收一个客户端读连接成功后,再异步接收新客户端连接
attachment.asynchronousServerSocketChannel.accept(attachment, this);
// 创建缓存,用于接收客户端的请求消息
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 进行异步读操作
result.read(buffer, buffer, new ReadCompletionHandler(result));
}
@Override
public void failed(Throwable exc, AsyncTimeServerHandler attachment) {
// TODO Auto-generated method stub
exc.printStackTrace();
attachment.latch.countDown();
}
}
解析请求消息并返回响应的ReadCompletionHandler类:
package com.servertest;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class ReadCompletionHandler implements CompletionHandler<Integer, ByteBuffer>{
private AsynchronousSocketChannel channel;
public ReadCompletionHandler(AsynchronousSocketChannel channel) {
// TODO Auto-generated constructor stub
if (this.channel == null) {
this.channel = channel;
}
}
@Override
public void completed(Integer result, ByteBuffer attachment) {
// TODO Auto-generated method stub
attachment.flip();
byte[] body = new byte[attachment.remaining()];
attachment.get(body);
try {
String req = new String(body, "UTF-8");
System.out.println("The time server receive order : " + req);
String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(req) ? new java.util.Date(
System.currentTimeMillis()).toString() : "BAD ORDER";
doWrite(currentTime);
}catch (Exception e) {
// TODO: handle exception
}
}
public void doWrite(String currentTime) {
if (currentTime != null && currentTime.length() > 0) {
byte[] bytes = (currentTime).getBytes();
ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
writeBuffer.put(bytes);
writeBuffer.flip();
channel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer buffer) {
// 如果没有发送完成,继续发送
if (buffer.hasRemaining()) {
channel.write(buffer, buffer, this);
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
// TODO Auto-generated method stub
try {
channel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
// TODO Auto-generated method stub
try {
this.channel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客户端主程序入口:
package com.clienttest;
public class TimeClientTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
int port = 8888;
// 通过一个独立的I/O线程创建异步时间服务器客户端handler,在实际的项目中,不需要独立的线程
new Thread(new AsyncTimeClientHandler("127.0.0.1", port), "AIO-AsyncTimeClientHandler-001").start();
}
}
客户端处理类:
package com.clienttest;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;
public class AsyncTimeClientHandler implements CompletionHandler<Void, AsyncTimeClientHandler>, Runnable{
private AsynchronousSocketChannel client;
private String host;
private int port;
private CountDownLatch latch;
public AsyncTimeClientHandler(String host, int port) {
// TODO Auto-generated constructor stub
this.host = host;
this.port = port;
try {
// 创建异步客户端通道
client = AsynchronousSocketChannel.open();
}catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
latch = new CountDownLatch(1);
// 与服务端创建连接
client.connect(new InetSocketAddress(host, port), this, this);
try {
latch.await();
}catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
try {
client.close();
}catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}
@Override
public void completed(Void result, AsyncTimeClientHandler attachment) {
// TODO Auto-generated method stub
byte[] req = "QUERY TIME ORDER".getBytes();
ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);
writeBuffer.put(req);
writeBuffer.flip();
client.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer buffer) {
// TODO Auto-generated method stub
if (buffer.hasRemaining()) {
client.write(buffer, buffer, this);
}else {
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
client.read(readBuffer, readBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer buffer) {
// TODO Auto-generated method stub
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String body;
try {
body = new String(bytes, "UTF-8");
System.out.println("Now is : " + body);
latch.countDown();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
// TODO Auto-generated method stub
try {
client.close();
latch.countDown();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
// TODO Auto-generated method stub
try {
client.close();
latch.countDown();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
@Override
public void failed(Throwable exc, AsyncTimeClientHandler attachment) {
// TODO Auto-generated method stub
exc.printStackTrace();
try {
client.close();
latch.countDown();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}