Java I/O 模型之 AIO

简介: Java AIO为我们提供了AsynchronousServerSocketChannel类,它是一个面向流监听套接字的异步通道,可以通过该类的open方法创建一个实例。

❤️ 个人主页:水滴技术
🚀 支持水滴:点赞👍 + 收藏⭐ + 留言💬
🌸 订阅专栏:Java 教程:从入门到精通

大家好,我是水滴~~

服务端API

创建服务端套接字的异步通道

Java AIO为我们提供了AsynchronousServerSocketChannel类,它是一个面向流监听套接字的异步通道,可以通过该类的open方法创建一个实例。

新创建的异步服务器套接字通道还没有绑定本地地址(IP地址+端口),通过bind方法来绑定一个本地地址,并且启动了监听。此时客户端已经可以连接了。

该通道是线程安全的,但同时只能有一个ACCEPT操作是进行中的。如果前一个线程还未完成ACCEPT操作,后一个线程发起ACCEPT操作,将会抛出AcceptPendingException异常。

// 打开一个异步的 ServerSocket 通道
AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();
// 绑定本地地址
serverSocketChannel.bind(new InetSocketAddress(8080));

接收客户端连接

AsynchronousServerSocketChannel类提供了两个accept方法,它们都是异步的,不会阻塞。下面我们使用带参数的方法来完成ACCEPT操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cjc62Af8-1649771737856)(https://secure2.wostatic.cn/static/gBmK7M8b6tGTcXMUaRJb8L/image.png)]

第一个参数是要附加到I/O操作的对象,可以为null

第二个参数是一个连接的结果处理器,即当有连接完成后,会自动调用该处理器CompletionHandler,来执行后面的内容。该处理器是一个泛型接口,第一个泛型类型是AsynchronousSocketChannel类,第二个泛型类型是前面提到的附加对象。

下面的示例代码,我们将AsynchronousServerSocketChannel对象做为附加对象,并使用函数式编程来创建CompletionHandler接口的实现。

CompletionHandler接口有两个方法需要我们来实现,completed方法用于客户端连接完成时调用;failed用于客户端连接失败时调用。

不管连接是成功还是失败,都要继续接收下一个连接,以保证服务端的工作。

// 接收客户端连接
serverSocketChannel.accept(serverSocketChannel, new CompletionHandler<AsynchronousSocketChannel, AsynchronousServerSocketChannel>() {
   
   
    @Override
    public void completed(AsynchronousSocketChannel result, AsynchronousServerSocketChannel attachment) {
   
   
        try {
   
   
            // 一个客户端连接后,继续接收下一个连接
            attachment.accept(attachment, this);
            // 申请一个1024个字节的缓冲区
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            // 读取客户端数据
            result.read(byteBuffer, byteBuffer, new ReadCompletionHandler(result));
        } catch (IOException e) {
   
   
            e.printStackTrace();
        }
    }

    @Override
    public void failed(Throwable exc, AsynchronousServerSocketChannel attachment) {
   
   
        // 一个客户端连失败,继续接收下一个连接
        attachment.accept(attachment, this);
    }
});

读取客户端数据

AsynchronousServerSocketChannel通道只负责监听客户端连接。当连接建立成功后,会为该连接创建一个AsynchronousSocketChannel通道,后续服务端与该客户端的I/O操作,都是通过该通道完成的。

该类的read方法用来读取客户端数据,此方法的第一个参数为ByteBuffer缓冲区,第二个参数为附加对象,第三个参数是读取数据的结果处理器。

在这里插入图片描述

该方法启动了一个异步读取操作,会将一个字节序列从该通道中读入给定的缓冲区中。处理程序是一个在读取操作完成(或失败)时调用的结果处理程序。当读取操作完成后,会传递一个读取的字节数,如果通道中流结束(另一端关闭通道),则字节数为-1。

在下面的代码示例中,为读取结果的处理程序创建了一个实现类ReadCompletionHandler,该类的构造方法传入AsynchronousSocketChannel实例,用来读取该通道中数据。

该类在读取完成缓冲区中数据后,会继续调用read方法,来继续读取下一报文。

static class ReadCompletionHandler implements CompletionHandler<Integer, ByteBuffer> {
   
   
   private final AsynchronousSocketChannel asynchronousSocketChannel;

    ReadCompletionHandler(AsynchronousSocketChannel asynchronousSocketChannel) {
   
   
        this.asynchronousSocketChannel = asynchronousSocketChannel;
    }

    @Override
    public void completed(Integer result, ByteBuffer attachment) {
   
   
        // 客户端关闭通道,字节数为-1
        if(result == -1) {
   
   
            System.out.printf("[%s] - 客户端断开连接!\n", Thread.currentThread().getName());
            try {
   
   
                // 关闭当前 Socket 通道
                asynchronousSocketChannel.close();
            } catch (IOException e) {
   
   
                e.printStackTrace();
            }
            return;
        }
        // 将缓冲区进行反转(刚才是写入,反转后变为读取)
        attachment.flip();
        // 读取缓冲区中的内容,并转为字符串
        String content = new String(attachment.array(), 0, result);
        System.out.printf("[%s] - 接收客户端发来的内容:%s\n", Thread.currentThread().getName(), content);
        // 清除缓冲区
        attachment.clear();
        // 继续读取下一报文
        asynchronousSocketChannel.read(attachment, attachment, new ReadCompletionHandler(asynchronousSocketChannel));
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
   
   
        System.out.printf("[%s] - 客户端断开连接!\n", Thread.currentThread().getName());
        try {
   
   
            // 关闭当前 Socket 通道
            asynchronousSocketChannel.close();
        } catch (IOException e) {
   
   
            e.printStackTrace();
        }
    }
}

客户端API

创建客户端套接字的异步通道

客户端可以通过AsynchronousSocketChannelopen静态方法,来创建一个异步通道。

// 打开一个异步的 Socket 通道
AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();

连接服务端

该异步通道通过connect方法来连接指定的服务端地址(IP地址+端口),该connect方法也是一个异步方法,同样可以指定结果处理器,但这次我们使用Future方式来实现。

Future是非阻塞的,可以通过isDone方法来检测是否执行完毕。在这里,我们使用get方法来阻塞获取结果,直到连接成功。

// 连接指定的服务端,并同步获取连接结果。
Future<Void> connectFuture = socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
// get()操作会阻塞,直到连接成功。
connectFuture .get();

向服务端写入数据

连接成功后,可以向该通道写入数据了。同样write方法也是一个异步的,这里我们也使用Future方式,并通过get方法阻塞获取结果。

// 申请一个1024字节的缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// 将控制台输入的内容写入缓冲区
byteBuffer.put("你好".getBytes());
// 反转缓冲区(从写入变为读取)
byteBuffer.flip();
// 将缓冲区中的内容写入到 Socket 通道中。get()操作会阻塞,直到写入成功。
socketChannel.write(byteBuffer).get();
// 清除缓冲区
byteBuffer.clear();
相关文章
|
2月前
|
机器学习/深度学习 分布式计算 Java
Java 大视界 -- Java 大数据机器学习模型在遥感图像土地利用分类中的优化与应用(199)
本文探讨了Java大数据与机器学习模型在遥感图像土地利用分类中的优化与应用。面对传统方法效率低、精度差的问题,结合Hadoop、Spark与深度学习框架,实现了高效、精准的分类。通过实际案例展示了Java在数据处理、模型融合与参数调优中的强大能力,推动遥感图像分类迈向新高度。
|
2月前
|
机器学习/深度学习 存储 Java
Java 大视界 -- Java 大数据机器学习模型在游戏用户行为分析与游戏平衡优化中的应用(190)
本文探讨了Java大数据与机器学习模型在游戏用户行为分析及游戏平衡优化中的应用。通过数据采集、预处理与聚类分析,开发者可深入洞察玩家行为特征,构建个性化运营策略。同时,利用回归模型优化游戏数值与付费机制,提升游戏公平性与用户体验。
|
2月前
|
机器学习/深度学习 算法 Java
Java 大视界 -- Java 大数据机器学习模型在舆情分析中的情感倾向判断与话题追踪(185)
本篇文章深入探讨了Java大数据与机器学习在舆情分析中的应用,重点介绍了情感倾向判断与话题追踪的技术实现。通过实际案例,展示了如何利用Java生态工具如Hadoop、Hive、Weka和Deeplearning4j进行舆情数据处理、情感分类与趋势预测,揭示了其在企业品牌管理与政府决策中的重要价值。文章还展望了多模态融合、实时性提升及个性化服务等未来发展方向。
|
3月前
|
Java 数据库连接 API
Java 对象模型现代化实践 基于 Spring Boot 与 MyBatis Plus 的实现方案深度解析
本文介绍了基于Spring Boot与MyBatis-Plus的Java对象模型现代化实践方案。采用Spring Boot 3.1.2作为基础框架,结合MyBatis-Plus 3.5.3.1进行数据访问层实现,使用Lombok简化PO对象,MapStruct处理对象转换。文章详细讲解了数据库设计、PO对象实现、DAO层构建、业务逻辑封装以及DTO/VO转换等核心环节,提供了一个完整的现代化Java对象模型实现案例。通过分层设计和对象转换,实现了业务逻辑与数据访问的解耦,提高了代码的可维护性和扩展性。
155 1
|
机器学习/深度学习 数据采集 算法
Java 大视界 -- Java 大数据机器学习模型在金融衍生品定价中的创新方法与实践(166)
本文围绕 Java 大数据机器学习模型在金融衍生品定价中的应用展开,分析定价现状与挑战,阐述技术原理与应用,结合真实案例与代码给出实操方案,助力提升金融衍生品定价的准确性与效率。
Java 大视界 -- Java 大数据机器学习模型在金融衍生品定价中的创新方法与实践(166)
|
5月前
|
编解码 JavaScript 前端开发
【Java进阶】详解JavaScript的BOM(浏览器对象模型)
总的来说,BOM提供了一种方式来与浏览器进行交互。通过BOM,你可以操作窗口、获取URL、操作历史、访问HTML文档、获取浏览器信息和屏幕信息等。虽然BOM并没有正式的标准,但大多数现代浏览器都实现了相似的功能,因此,你可以放心地在你的JavaScript代码中使用BOM。
150 23
|
10月前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
113 2
Java I/O流面试之道
|
11月前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
145 1
|
Java
java中I/O流之字节流和字符流学习总结(下)
java中I/O流之字节流和字符流学习总结(下)
155 0
java中I/O流之字节流和字符流学习总结(下)
|
移动开发 Java 数据库
java中I/O流之字节流和字符流学习总结(上)
java中I/O流之字节流和字符流学习总结(上)
170 0
java中I/O流之字节流和字符流学习总结(上)

热门文章

最新文章