AIO模型是java中提供的异步非阻塞网络IO模型。
我们可以调用JDK提供的相关方法实现AIO模型。
与NIO不同,AIO需要一个连接注册读写事件和回调方法,当进行读写操作时,只须调用API的read或write方法即可。这两种方法都是异步的,
- 对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;
- 对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。
即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。
回调
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。回调方法是任何一个被以该回调方法为其第一个参数的其它方法调用的方法。很多时候,回调是一个当某些事件发生时被调用的方法。
AIO中的回调函数
- java.nio.channels.AsynchronousServerSocketChannel public abstract void accept(A attachment,
CompletionHandler<AsynchronousSocketChannel,? super A>
handler)
accept方法用于接收连接请求,第一个参数是附件,第二个参数是收到请求后的接收处理器(回调)。对应的处理器泛型,第一个参数是处理结果(这里为AsynchronousSocketChannel,即接收到的请求channel),第二个参数是附件。
- java.nio.channels.AsynchronousSocketChannel public abstract void connect(SocketAddress remote,Aattachment,CompletionHandler<Void,?
super A> handler)
连接服务器,第一个参数为连接的目标地址,第二参数为附件,第三个参数为连接处理器。
对应的处理器泛型,第一个参数为空(即Void),第二个参数为附件;
- public final void read(ByteBuffer dst, A attachment, CompletionHandler<Integer,? super A> handler)
读取数据,第一个参数是数据读取到的目标缓存,第二个参数是附件,第三个参数是读取结束后的处理器。
对应的处理器泛型,第一个参数是读取的字节数,第二个是附件类型;
- public final void write(ByteBuffer src, A attachment, CompletionHandler<Integer,? super A> handler)
写入数据,第一个参数是数据写入的缓存,第二个参数是附件,第三个参数是写结束后的处理器。
对应的处理器泛型,第一个参数是写入的字节数,第二个是附件类型;
AIO模型我觉得重点就是这几个事件对应的回调函数的传参问题。
继承CompletionHandler接口时,有两个方法需要实现,分别是completed和failed,当操作完成后,会回调completed,出现异常失败时会回调failed。
- completed:
操作完成时,回调completed函数,其有result和attchment两个参数:result是操作完成后的操作结果;attchment是在进行回调时可以传入的附件,用于回调其内 的操作
- failed:
操作异常时回调failed函数,其有exc和attachment两个参数;exc即进行操作时出现的异常;attachment和completed中的一致,为在进行回调时传入的附件,用于回调内的操作。
注意:上述方法是异步调用所以事件的处理何时开始何时结束取决于事件本身。
AIO模型代码
public class ServerAIO {
private int port = 5676;
private AsynchronousServerSocketChannel serverChannel;
private CountDownLatch latch;
public AsynchronousServerSocketChannel getServerChannel() {
return serverChannel;
}
public ServerAIO(){
try {
serverChannel = AsynchronousServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(port));
} catch (IOException e) {
e.printStackTrace();
}
}
public CountDownLatch getLatch() {
return latch;
}
public void startAIOServer(){
latch = new CountDownLatch(1);
serverChannel.accept(this,new AccpetHandler());//阻塞方法
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// new AcceptHandler() 回调的时候用
//为什么携带ServerAIO
// 服务器一直监听客户端的连接
}
//wait 锁 sleep join conuntDownLatch
public static void main(String[] args) {
new ServerAIO().startAIOServer();
}
}
public class ClientAIO {
private int port = 5676;
private String IP = "localhost";//127.0.0.1
private AsynchronousSocketChannel socketChannel;
private CountDownLatch latch;
public CountDownLatch getLatch() {
return latch;
}
public ClientAIO() {
try {
socketChannel = AsynchronousSocketChannel.open();
} catch (IOException e) {
e.printStackTrace();
}
}
public void startClient() {
latch = new CountDownLatch(1);
socketChannel.connect(new InetSocketAddress(IP, port),
this, new ConnectHandler(socketChannel));
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//主线程 发消息
ClientAIO clienrtAIO = new ClientAIO();
clienrtAIO.startClient();
}
}
public class AccpetHandler implements
CompletionHandler<AsynchronousSocketChannel, ServerAIO>
{
private ByteBuffer readBuffer;
// AsynchronousSocketChannel :accept 的返回值
@Override
public void completed(AsynchronousSocketChannel socketChannel,
ServerAIO serverAIO) {
// (1)继续监听其他用户的连接请求
serverAIO.getServerChannel().accept(serverAIO, this); //阻塞这里
//操作系统
//当成功监听一个用户连接之后 接着监听第二个
// socketChannel 成功监听之后的用户对应的channel
//(2)接收建立好连接的这个用户的请求数据
readBuffer = ByteBuffer.allocate(1024);
// readBuffer.flip();
socketChannel.read(readBuffer, readBuffer,
new ReadHandler(socketChannel));
//异步发出read请求
}
@Override
public void failed(Throwable exc, ServerAIO serverAIO) {
serverAIO.getLatch().countDown();
}
}
public class ClientReadHandler implements CompletionHandler
<Integer, ByteBuffer> {
private ByteBuffer sendByteBuffer;
private AsynchronousSocketChannel socketChannel;
public ClientReadHandler(AsynchronousSocketChannel socketChannel) {
this.socketChannel = socketChannel;
}
@Override
public void completed(Integer num, ByteBuffer readBuffer) {
System.out.println(new String(readBuffer.array(), 0, num));
String str = "client say hello";
sendByteBuffer = ByteBuffer.allocate(1024);
sendByteBuffer.put(str.getBytes());
sendByteBuffer.flip();//
socketChannel.write(sendByteBuffer, sendByteBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
ByteBuffer readBuffer1 = ByteBuffer.allocate(1024);
socketChannel.read(readBuffer1, readBuffer1,
new ClientReadHandler(socketChannel));
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
}
});
}
@Override
public void failed(Throwable exc, ByteBuffer readBuffer) {
}
}
public class ConnectHandler implements CompletionHandler<Void,ClientAIO> {
private AsynchronousSocketChannel socketChannel;
private ByteBuffer readBuffer;
public ConnectHandler(AsynchronousSocketChannel socketChannel) {
this.socketChannel = socketChannel;
readBuffer = ByteBuffer.allocate(1024);
}
@Override
public void completed(Void result, ClientAIO attachment) {
String s = "client say hello";
ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
sendBuffer.clear();
sendBuffer.put(s.getBytes());
sendBuffer.flip();
socketChannel.write(sendBuffer, sendBuffer, new CompletionHandler<
Integer, ByteBuffer>() {
@Override
public void completed(Integer num, ByteBuffer buffer) {
System.out.println("num: " + num);
if (buffer.hasRemaining()) {
socketChannel.write(buffer, buffer, this);
} else {
socketChannel.read(readBuffer, readBuffer,
new ClientReadHandler(socketChannel));
//可以继续接收服务器的消息
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
}
});
}
@Override
public void failed(Throwable exc, ClientAIO clienrtAIO) {
exc.printStackTrace();
clienrtAIO.getLatch().countDown();
}
}
public class ReadHandler implements CompletionHandler<Integer,ByteBuffer> {
private ByteBuffer sendBuffer;
private AsynchronousSocketChannel socketChannel;
public ReadHandler(AsynchronousSocketChannel socketChannel) {
this.socketChannel = socketChannel;
}
@Override
public void completed(Integer num, final ByteBuffer readBuffer) {
//这个readBuffer中已经有数据
// (1)
System.out.println(num);
System.out.println(new String(readBuffer.array(), 0, num));
readBuffer.clear();
// (2)给客户端回数据
sendBuffer = ByteBuffer.allocate(1024);
String str = "server receievre your msg";
sendBuffer.put(str.getBytes());
sendBuffer.flip();
//客户端对应的channel
socketChannel.write(sendBuffer, sendBuffer,
new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer buffer) {
//数据发成功 服务器继续收取这个用户的请求
if (buffer.hasRemaining()) {
socketChannel.write(buffer, buffer, this);
} else {
socketChannel.read(readBuffer, readBuffer,
new ReadHandler(socketChannel));
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
}
});
}
@Override
public void failed(Throwable exc, ByteBuffer readBuffer) {
exc.printStackTrace();
try {
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}