Java网络编程IO系列之AIO

2 篇文章 0 订阅
1 篇文章 0 订阅

AIO简介

Java AIO 是Java 7发布的新特性,支持异步方式处理消息,被称为NIO2.0版本,是NIO的增强版。AIO为异步非阻塞IO,通过接收IO完成后的通知的方式进行结果处理。java中的AIO依赖于系统提供的异步非阻塞IO模型,底层使用AIO的系统调用进行IO请求及通知接收(关于AIO模型见Linux五种网络IO模型)

AIO工具类

Java网络IO中的AIO实现主要借助AsynchronousServerSocketChannel、AsynchronousSocketChannel、CompletionHandler、AsynchronousChannelGroup,这几个类均位于java.nio包,下面对各自相关使用简单介绍一下。

AsynchronousChannelGroup

用于资源共享的一组异步通道,异步通道组封装了处理绑定到组的asynchronous channels启动的I / O操作完成所需的机制。 组具有关联的线程池,任务将提交到该线程池以处理I / O事件,并分派给completion-handlers ,该队列消耗对组中通道执行的异步操作的结果。 除了处理I / O事件之外,池化线程还可以执行支持异步I / O操作执行所需的其他任务。

构造方式
public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor,int initialSize)

创建具有给定线程池的异步通道组,该线程池根据需要创建新线程。

public static AsynchronousChannelGroup withFixedThreadPool(int nThreads,ThreadFactory threadFactory)

创建具有固定线程池的异步通道组。

public static AsynchronousChannelGroup withThreadPool(ExecutorService executor)

创建给定线程池的异步通道组

常用方法

void shutdown()
标记当前组被关闭,后续有异步套接字通道绑定本组会抛出异常,当所有的套接字请求执行完毕后,该组会被正式关闭。
** void shutdownNow()**
立即关闭当前组,所有套接字通道被关闭,但不会中断当前当前接收完数据正在进行处理的线程。当所有执行CompleteHandler的线程执行完毕后正式关闭。
** boolean awaitTermination(long timeout, TimeUnit unit)**
阻塞等待关闭当前组。

AsynchronousServerSocketChannel

AsynchronousServerSocketChannel对应于BIO中的ServerSocketChannel,用于服务端接收连接,建立套接字。进行异步处理。

构造方式

与ServerSocketChannel相似,使用静态方法进行构造。

static AsynchronousServerSocketChannel open(AsynchronousChannelGroup group)

绑定指定异步套接字通道组构造服务端异步套接字通道,

static AsynchronousServerSocketChannel open()

使用默认异步套接字通道组构建服务端异步套接字通道。

主要方法

AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)
绑定本地套接字地址,指定等待建立连接队列的长度为backlog,设置值需大于0,小于等于0时为默认值50。
AsynchronousServerSocketChannel bind(SocketAddress local)
绑定本地套接字,此时等待建立连接队列的长度为默认值50
void accept(A attachment,CompletionHandler<AsynchronousSocketChannel,? super A> handler);
接收套接字请求,请求数据接收完成后交于CompletionHandler对象实例handler处理,同时将泛型参数Attachment传递给handler用于识别上下文。
Future accept()
接收套接字请求,获取Future对象,接收到新连接后通过Future对象获取AsynchronousSocketChannel对象。

accept()与accept(A attachment,CompletionHandler<AsynchronousSocketChannel,? super A> handler)区别

首先看一下Future接口

public interface Future<V> {

    /**
     * Attempts to cancel execution of this task.  This attempt will
     * fail if the task has already completed, has already been cancelled,
     * or could not be cancelled for some other reason. If successful,
     * and this task has not started when {@code cancel} is called,
     * this task should never run.  If the task has already started,
     * then the {@code mayInterruptIfRunning} parameter determines
     * whether the thread executing this task should be interrupted in
     * an attempt to stop the task.
     *
     * <p>After this method returns, subsequent calls to {@link #isDone} will
     * always return {@code true}.  Subsequent calls to {@link #isCancelled}
     * will always return {@code true} if this method returned {@code true}.
     *
     * @param mayInterruptIfRunning {@code true} if the thread executing this
     * task should be interrupted; otherwise, in-progress tasks are allowed
     * to complete
     * @return {@code false} if the task could not be cancelled,
     * typically because it has already completed normally;
     * {@code true} otherwise
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * Returns {@code true} if this task was cancelled before it completed
     * normally.
     *
     * @return {@code true} if this task was cancelled before it completed
     */
    boolean isCancelled();

    /**
     * Returns {@code true} if this task completed.
     *
     * Completion may be due to normal termination, an exception, or
     * cancellation -- in all of these cases, this method will return
     * {@code true}.
     *
     * @return {@code true} if this task completed
     */
    boolean isDone();

    /**
     * Waits if necessary for the computation to complete, and then
     * retrieves its result.
     *
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     *
     * @param timeout the maximum time to wait
     * @param unit the time unit of the timeout argument
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     * @throws TimeoutException if the wait timed out
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

再观察一下CompletionHandler接口

public interface CompletionHandler<V,A> {

    /**
     * Invoked when an operation has completed.
     *
     * @param   result
     *          The result of the I/O operation.
     * @param   attachment
     *          The object attached to the I/O operation when it was initiated.
     */
    void completed(V result, A attachment);

    /**
     * Invoked when an operation fails.
     *
     * @param   exc
     *          The exception to indicate why the I/O operation failed
     * @param   attachment
     *          The object attached to the I/O operation when it was initiated.
     */
    void failed(Throwable exc, A attachment);

可以看到Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行,而CompletionHandler提供的方法则简单直接,通过自定义对象的方式接收任务结束完成时的回调方法(completed或failed)。单纯使用Future时需要主动轮询任务结果或者阻塞获取结果,而CompletionHandler则采用被动回调的方式获取,因此更推荐使用CompletionHandler。

CompletionHandler

如上文所述,CompletionHandler是一个泛型接口,用于接收AIO异步回调。其中V未回调结果类型,A为连接附带参数attachment。

AIO通信实践

服务端

/**
 * @author Mr.m
 * 2020/12/11
 */
public class AsynchronousServer {
    public static void main(String[] args) throws Exception {
        AsynchronousChannelGroup asynchronousChannelGroup = AsynchronousChannelGroup.withCachedThreadPool(Executors.newCachedThreadPool(), 10);
        AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(asynchronousChannelGroup);
        asynchronousServerSocketChannel.bind(new InetSocketAddress(8889));
        Future<AsynchronousSocketChannel> asynchronousSocketChannelFuture;
        while (true) {
            asynchronousSocketChannelFuture = asynchronousServerSocketChannel.accept();
            System.out.println("阻塞接收连接...");
            AsynchronousSocketChannel asynchronousSocketChannel = asynchronousSocketChannelFuture.get();
            System.out.println("接收请求:" + asynchronousSocketChannel.getRemoteAddress().toString());
            new AsynchronousChannelConnectionHandler(asynchronousSocketChannel).handle();
        }
    }
}

基础实现比较简单,构造一个AsynchronousServerSocketChannel对象,死循环接收客户端连接。连接建立后交由AsynchronousChannelConnectionHandler 处理,AsynchronousChannelConnectionHandler 代码如下:

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

/**
 * @author Mr.m
 * 2021/1/4
 */
public class AsynchronousChannelConnectionHandler {

    AsynchronousSocketChannel asynchronousSocketChannel;

    public AsynchronousChannelConnectionHandler(AsynchronousSocketChannel asynchronousSocketChannel) {
        this.asynchronousSocketChannel = asynchronousSocketChannel;
    }

    public void handle() {
        final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        asynchronousSocketChannel.read(byteBuffer, null, new CompletionHandler<Integer, Object>() {
            @Override
            public void completed(Integer result, Object attachment) {
                if (result > 0) {
                    System.out.println("请求内容:" + new String(byteBuffer.array()));
                    String resp = "操作成功";
                    ByteBuffer writeBuffer = ByteBuffer.wrap(resp.getBytes());
                    asynchronousSocketChannel.write(writeBuffer);
                }
            }

            @Override
            public void failed(Throwable exc, Object attachment) {

            }
        });
    }
}

AsynchronousChannelConnectionHandler会对请求内容读取,简单处理,并返回结果。

客户端

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.Future;

/**
 * @author Mr.m
 * 2021/1/4
 */
public class AioClient {
    public static void main(String[] args) throws IOException, InterruptedException {
        AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open();
        System.out.println("发起连接请求");
        Future<Void> future = asynchronousSocketChannel.connect(new InetSocketAddress("localhost", 8889));
        //阻塞等待连接建立
        future.get();
        String req = "hello ,我是" + asynchronousSocketChannel.getLocalAddress().toString();
        ByteBuffer byteBuffer = ByteBuffer.allocate(req.getBytes().length);
        byteBuffer.put(req.getBytes());
        byteBuffer.flip();
        System.out.println("开始写入请求内容");
        asynchronousSocketChannel.write(byteBuffer, null, new CompletionHandler<Integer, Object>() {
            @Override
            public void completed(Integer result, Object attachment) {
                System.out.println("请求内容传输完成");
                ByteBuffer respBuffer = ByteBuffer.allocate(1024);
                asynchronousSocketChannel.read(respBuffer, null, new CompletionHandler<Integer, Object>() {

                    @Override
                    public void completed(Integer result, Object attachment) {
                        String resp = new String(respBuffer.array());
                        System.out.println("收到回复:" + resp);
                    }

                    @Override
                    public void failed(Throwable exc, Object attachment) {

                    }
                });
            }

            @Override
            public void failed(Throwable exc, Object attachment) {

            }
        });
        Thread.sleep(10000L);
    }
}

客户端构建一个AsynchronousSocketChannel ,阻塞等待连接建立,异步写入请求内容,异步获取返回结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值