一 前言
简介
AIO: 事件驱动I/O,也叫NIO 2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。不需要过多的Selector对注册的通道进行轮询即可实现异步读写,从而简化了NIO的编程模型。
不多说,上代码,都有注释
二 Java代码
1.服务端
package dcocd.netty.tool.io.aio.server;
/**
* AIO Server 启动
*
* @author guohongjun@dcocd.cn
* @Date 2020/5/13 11:37
*/
public class AioServer {
/**
* 默认端口号
*/
private static int DEFAULT_PORT = 12345;
/**
* AIO Server处理器
*/
private static AioServerHandler aioServerHandler;
/**
* 客户端数量
*/
public volatile static long clientCount = 0;
public static void start() {
start(DEFAULT_PORT);
}
public static synchronized void start(int port) {
if (aioServerHandler != null) {
return;
}
aioServerHandler = new AioServerHandler(port);
new Thread(aioServerHandler, "aio-server-" + port).start();
}
public static void main(String[] args) {
AioServer.start();
}
}
2.服务端处理器
package dcocd.netty.tool.io.aio.server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.CountDownLatch;
/**
* AIO Server处理器
*
* @author guohongjun@dcocd.cn
* @Date 2020/5/13 14:18
*/
public class AioServerHandler implements Runnable {
private static Logger logger = LoggerFactory.getLogger(AioServerHandler.class);
/**
* 作用:在完成一组正在执行的操作之前,允许当前的线程一直阻塞
*/
protected CountDownLatch countDownLatch;
/**
* AIO Server 服务端通道
*/
protected AsynchronousServerSocketChannel socketChannel;
/**
* 构造方法
*
* @param port 端口号
*/
public AioServerHandler(int port) {
try {
// 创建服务通道
socketChannel = AsynchronousServerSocketChannel.open();
// 绑定端口
socketChannel.bind(new InetSocketAddress(port));
logger.info("aio-server start successful by port : " + port);
} catch (IOException e) {
logger.error("aio-server create error : " + e.getMessage());
}
}
@Override
public void run() {
// CountDownLatch 初始化
// 它的作用:在完成一组正在执行的操作之前,允许当前的线程一直阻塞;
// 此处,让线程在此阻塞,防止服务端执行完成后退出,也可以使用while(true)+sleep
// 生产环境就不需要担心这个问题,因为服务端是不会退出的
countDownLatch = new CountDownLatch(1);
// 用于接收客户端的链接
socketChannel.accept(this, new AioServerAcceptHandler());
try {
// 使当前线程等待直到锁存器倒计时到零
countDownLatch.await();
} catch (InterruptedException e) {
logger.error("AioServerHandler run() CountDownLatch await() error " + e.getMessage());
}
}
}
3.服务端链接处理器
package dcocd.netty.tool.io.aio.server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
/**
* 作为 Aio Server handler 接收客户端连接
*
* @author guohongjun@dcocd.cn
* @Date 2020/5/13 14:32
*/
public class AioServerAcceptHandler implements CompletionHandler<AsynchronousSocketChannel, AioServerHandler> {
private static Logger logger = LoggerFactory.getLogger(AioServerAcceptHandler.class);
/**
* Invoked when an operation has completed.
* 在操作完成时调用,即链接客户端成功后
*
* @param channel I/O操作的结果 通道
* @param aioServerHandler Aio Server 服务端处理器
*/
@Override
public void completed(AsynchronousSocketChannel channel, AioServerHandler aioServerHandler) {
// 继续接收其他客户端的请求
AioServer.clientCount++;
logger.info("aio-client on line count : " + AioServer.clientCount);
// 使 Aio Server 服务端处理器的服务端通道接受客户端连接
aioServerHandler.socketChannel.accept(aioServerHandler, this);
// 创建新的 Buffer,并开辟一个1M的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 异步读,第三个参数为接收消息回调的业务 handler
channel.read(buffer, buffer, new AioServerReadHandler(channel));
}
/**
* Invoked when an operation fails.
* 操作失败时调用
*
* @param exc 指示I/O操作失败原因的异常
* @param aioServerHandler Aio Server 服务端处理器
*/
@Override
public void failed(Throwable exc, AioServerHandler aioServerHandler) {
logger.error("aio-server received aio-client connection error : " + exc.getMessage());
// 减少闩锁的计数
aioServerHandler.countDownLatch.countDown();
logger