java 7引入AIO 基于linux epoll, window iocp
异步 I/O(简称 AIO)
- AIO 的核心概念:发起非阻塞方式的 I/O 操作。当 I/O 操作完成时通知。
- 应用程序的责任就是:什么时候发起操作? I/O 操作完成时通知谁?
AIO 的 I/O 操作,有两种方式的 API 可以进行:Future 方式 和 Callback 方式。
Future 方式:即提交一个 I/O 操作请求(accept/read/write),返回一个 Future。然后您可以对 Future 进行检查(调用get(timeout)),确定它是否完成,或者阻塞 IO 操作直到操作正常完成或者超时异常。使用 Future 方式很简单,需要注意的是,因为Future.get()
是同步的,所以如果不仔细考虑使用场合,使用 Future 方式可能很容易进入完全同步的编程模式,从而使得异步操作成为一个摆设。如果这样,那么原来旧版本的 Socket API 便可以完全胜任,大可不必使用异步 I/O.
Callback 方式:即提交一个 I/O 操作请求,并且指定一个 CompletionHandler
。当异步 I/O 操作完成时,便发送一个通知,此时这个 CompletionHandler 对象的 completed 或者 failed 方法将会被调用。
JAVA AIO 示例代码:
package JAVA_IO;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class AIOServer {
public final static int PORT = 9888;
private AsynchronousServerSocketChannel server;
public AIOServer() throws IOException {
server = AsynchronousServerSocketChannel.open().bind(
new InetSocketAddress(PORT));
}
public void startWithFuture() throws InterruptedException,
ExecutionException, TimeoutException {
while (true) {// 循环接收客户端请求
Future<AsynchronousSocketChannel> future = server.accept();
AsynchronousSocketChannel socket = future.get();// get() 是为了确保 accept 到一个连接
handleWithFuture(socket);
}
}
public void handleWithFuture(AsynchronousSocketChannel channel) throws InterruptedException, ExecutionException, TimeoutException {
ByteBuffer readBuf = ByteBuffer.allocate(2);
readBuf.clear();
while (true) {// 一次可能读不完
//get 是为了确保 read 完成,超时时间可以有效避免DOS攻击,如果客户端一直不发送数据,则进行超时处理
Integer integer = channel.read(readBuf).get(10, TimeUnit.SECONDS);
System.out.println("read: " + integer);
if (integer == -1) {
break;
}
readBuf.flip();
System.out.println("received: " + Charset.forName("UTF-8").decode(readBuf));
readBuf.clear();
}
}
public void startWithCompletionHandler() throws InterruptedException,
ExecutionException, TimeoutException {
server.accept(null,
new CompletionHandler<AsynchronousSocketChannel, Object>() {
public void completed(AsynchronousSocketChannel result, Object attachment) {
server.accept(null, this);// 再此接收客户端连接
handleWithCompletionHandler(result);
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
}
});
}
public void handleWithCompletionHandler(final AsynchronousSocketChannel channel) {
try {
final ByteBuffer buffer = ByteBuffer.allocate(4);
final long timeout = 10L;
channel.read(buffer, timeout, TimeUnit.SECONDS, null, new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment) {
System.out.println("read:" + result);
if (result == -1) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
return;
}
buffer.flip();
System.out.println("received message:" + Charset.forName("UTF-8").decode(buffer));
buffer.clear();
channel.read(buffer, timeout, TimeUnit.SECONDS, null, this);
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) throws Exception {
// new AIOServer().startWithFuture();
new AIOServer().startWithCompletionHandler();
Thread.sleep(100000);
}
}
client 代码
package JAVA_IO;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
public class AIOClient {
public static void main(String... args) throws Exception {
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
client.connect(new InetSocketAddress("localhost", 9888)).get();
client.write(ByteBuffer.wrap("123456789".getBytes()));
Thread.sleep(1111111);
}
}