主要对象
AsynchronousChannelGroup
异步channel的分组管理,目的是为了资源共享。一个AsynchronousChannelGroup绑定一个线程池,这个线程池执行两个任务:处理IO事件和派发CompletionHandler。AsynchronousServerSocketChannel创建的时候可以传入一个AsynchronousChannelGroup,那么通过AsynchronousServerSocketChannel创建的AsynchronousSocketChannel将同属于一个组,共享资源。
AsynchronousChannelGroup允许绑定不同的线程池,通过三个静态方法来创建:
public static AsynchronousChannelGroup withFixedThreadPool(int nThreads,
ThreadFactory threadFactory)
throws IOException
public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor,
int initialSize)
public static AsynchronousChannelGroup withThreadPool(ExecutorService executor)
throws IOException
AsynchronousServerSocketChannel
ServerSocket的aio版本,创建TCP服务端,绑定地址,监听端口等。
AsynchronousSocketChannel
面向流的异步socket channel,表示一个连接。
CompletionHandler
异步IO操作结果的回调接口,用于定义在IO操作完成后所作的回调工作。AIO的API允许两种方式来处理异步操作的结果:返回的Future模式或者注册CompletionHandler,推荐用CompletionHandler的方式,这些handler的调用是由AsynchronousChannelGroup的线程池派发的。显然,线程池的大小是性能的关键因素。
CompletionHandler有三个方法,分别对应于处理成功、失败、被取消(通过返回的Future)情况下的回调处理:
public interface CompletionHandler<V,A> {
void completed(V result, A attachment);
void failed(Throwable exc, A attachment);
void cancelled(A attachment);
}
代码示例
下面就是通过AsynchronousServerSocketChannel实现的一个简单的EchoServer,服务器会打印出收到的客户端输入,并把输入写回客户端。(注:代码只有在JDK1.7下才能编译通过)
public class AIOEchoServer {
private AsynchronousServerSocketChannel server;
public static void main(String[] args) throws IOException {
AIOEchoServer aioServer = new AIOEchoServer();
aioServer.init("localhost", 6025);
}
private void init(String host, int port) throws IOException {
//ChannelGroup用来管理共享资源
AsynchronousChannelGroup group = AsynchronousChannelGroup.withCachedThreadPool(Executors.newCachedThreadPool(), 10);
server = AsynchronousServerSocketChannel.open(group);
//通过setOption配置Socket
server.setOption(StandardSocketOptions.SO_REUSEADDR, true);
server.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
//绑定到指定的主机,端口
server.bind(new InetSocketAddress(host, port));
System.out.println("Listening on " + host + ":" + port);
//输出provider
System.out.println("Channel Provider : " + server.provider());
//等待连接,并注册CompletionHandler处理内核完成后的操作。
server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
final ByteBuffer buffer = ByteBuffer.allocate(1024);
@Override
public void completed(AsynchronousSocketChannel result, Object attachment) {
System.out.println("waiting....");
buffer.clear();
try {
//把socket中的数据读取到buffer中
result.read(buffer).get();
buffer.flip();
System.out.println("Echo " + new String(buffer.array()).trim() + " to " + result);
//把收到的直接返回给客户端
result.write(buffer);
buffer.flip();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
try {
//关闭处理完的socket,并重新调用accept等待新的连接
result.close();
server.accept(null, this);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void failed(Throwable exc, Object attachment) {
System.out.print("Server failed...." + exc.getCause());
server.accept(null, this);
}
});
//因为AIO不会阻塞调用进程,因此必须在主进程阻塞,才能保持进程存活。
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Future对象的说明
概念
Future对象的get()方法会阻塞该线程,所以这种方式是阻塞式的异步IO。
示例
while (true) {
Future<AsynchronousSocketChannel> future = serverSocketChannel.accept();
AsynchronousSocketChannel socketChannel = null;
try {
socketChannel = future.get();
socketChannel.write(ByteBuffer.wrap("ssss".getBytes("UTF-8")));
} catch (Exception e) {
e.printStackTrace();
}
}