AIO异步非阻塞网络编程

AIO 的全称是 asynchronized IO,是从 JDK 7 开始支持的。AIO 不是在 IO 准备好时再通知线程的,而是在 IO 操作已经完成后,再给线程发出通知的。因此,AIO 是完全不会阻塞的。AIO 的特点如下:

  • 读完了再通知线程。

  • 不会加快 IO,只是在读完后进行通知。

  • 使用回调函数,进行业务处理。

AIO 需要使用异步通道,即 AsynchronousServerSocketChannel。其中,accept() 方法主要负责两件事:一件事是发起 accept 请求,告诉系统可以开始监听端口了;另一件事是注册 CompletionHandler 实例,当有客户端进行连接时:如果连接成功,就执行 CompletionHandler.completed() 方法;如果连接失败,就执行 CompletionHandler.failed() 方法。因此,accept() 方法不会被阻塞。

下面使用 AIO 分别编码实现客户端和服务器端。客户端的代码如下:

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.charset.Charset;

public class SimpleAIOClient {
    static final int PORT = 9000;
    public static void main(String[] args) throws Exception {
        // 用于读取数据的 ByteBuffer
        ByteBuffer bba = ByteBuffer.allocate(1024);
        Charset ctf = Charset.forName("utf-8");
        try (AsynchronousSocketChannel asc = AsynchronousSocketChannel.open()) {
            // 连接远程服务器
            asc.connect(new InetSocketAddress("127.0.0.1", PORT)).get();
            bba.clear();
            // 从 clientChannel 中读取数据
            asc.read(bba).get();
            bba.flip();
            // 将 buff 中内容转换为字符串
            String str = ctf.decode(bba).toString();
            System.out.println("由服务器端发送的信息:" + str);
        }
    }
}

服务器端的代码如下:

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.Future;

public class SimpleAIOServer {
    static final int PORT = 9000;
    public static void main(String[] args) throws Exception {
        try (AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open()) {
            // 在指定的地址、端口处进行监听
            assc.bind(new InetSocketAddress(PORT));
            while (true) {
                // 采用循环接受来自客户端的连接
                Future<AsynchronousSocketChannel> ft = assc.accept();
                // 获取连接完成后返回的 AsynchronousSocketChannel
                AsynchronousSocketChannel asc = ft.get();
                // 执行输出
                asc.write(ByteBuffer.wrap("你好!".getBytes("UTF-8"))).get();
            }
        }
    }
}

先运行服务器端,再运行客户端。运行结果如下:

     由服务器端发送的信息:你好!