Java AIO 编程

转载自 java aio 编程

Java NIO (JSR 51)定义了Java new I/O API,提案2000年提出,2002年正式发布。 JDK 1.4起包含了相应的API实现。
JAVA NIO2 (JSR 203)定义了更多的 New I/O APIs, 提案2003提出,直到2011年才发布, 最终在JDK 7中才实现。
JSR 203除了提供更多的文件系统操作API(包括可插拔的自定义的文件系统), 还提供了对socket和文件的异步 I/O操作。 同时实现了JSR-51提案中的socket channel全部功能,包括对绑定, option配置的支持以及多播multicast的实现。

当前很多的项目还停留在JAVA NIO的实现上, 对JAVA AIO(asynchronous I/O)着墨不多。 本文整理了一些关于JAVA AIO的介绍,以及netty对AIO的支持。
以下内容只针对socket的I/O操作, 不涉及对文件的处理。

JDK AIO API

首先介绍以下I/O模型。
Unix定义了五种I/O模型, 下图是五种I/O模型的比较。

  • 阻塞I/O
  • 非阻塞I/O
  • I/O复用(select、poll、linux 2.6种改进的epoll)
  • 信号驱动IO(SIGIO)
  • 异步I/O(POSIX的aio_系列函数)


UNP Ch6.2 I/O models

POSIX把I/O操作划分成两类:

  • 同步I/O: 同步I/O操作导致请求进程阻塞,直至操作完成
  • 异步I/O: 异步I/O操作不导致请求阻塞
    所以Unix的前四种I/O模型都是同步I/O, 只有最后一种才是异步I/O。

传统的Java BIO (blocking I/O)是Unix I/O模型中的第一种。
Java NIO中如果不使用select模式,而只把channel配置成nonblocking则是第二种模型。
Java NIO select实现的是一种多路复用I/O。 底层使用epoll或者相应的poll系统调用, 参看我以前整理的一篇文章: java 和netty epoll实现 
第四种模型JDK应该是没有实现。
Java NIO2增加了对第五种模型的支持,也就是AIO。

OpenJDK在不同平台上的AIO实现

在不同的操作系统上,AIO由不同的技术实现。
通用实现可以查看这里。
Windows上是使用完成接口(IOCP)实现,可以参看WindowsAsynchronousServerSocketChannelImpl,
其它平台上使用aio调用UnixAsynchronousServerSocketChannelImpl, UnixAsynchronousSocketChannelImpl, SolarisAsynchronousChannelProvider

常用类

  • AsynchronousSocketChannel
    • Asynchronous connect
    • Asynchronous read/write
    • Asynchronous scatter/gather (multiple buffers)
    • Read/write operations support timeout
    • failed method invoked with timeout exception
    • Implements NetworkChannel for binding, setting socket options, etc

AsynchronousServerSocketChannel
还实现了Asynchronous accept

AsynchronousDatagramChannel

  • Asynchronous read/write (connected)
  • Asynchronous receive/send (unconnected)
  • Implements NetworkChannel for binding, setting socket options, etc.
  • Implements MulticastChannel
  • CompletionHandler

Java AIO 例子

异步channel API提供了两种方式监控/控制异步操作(connect,accept, read,write等)。第一种方式是返回java.util.concurrent.Future对象, 检查Future的状态可以得到操作是否完成还是失败,还是进行中, future.get阻塞当前进程。
第二种方式为操作提供一个回调参数java.nio.channels.CompletionHandler,这个回调类包含completed,failed两个方法。
channel的每个I/O操作都为这两种方式提供了相应的方法, 你可以根据自己的需要选择合适的方式编程。

下面以一个最简单的Time服务的例子演示如何使用异步I/O。 客户端连接到服务器后服务器就发送一个当前的时间字符串给客户端。 客户端毋须发送请求。 逻辑很简单。

Server实现

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class Server {private static Charset charset = Charset.forName("US-ASCII");private static CharsetEncoder encoder = charset.newEncoder();public static void main(String[] args) throws Exception {AsynchronousChannelGroup group = AsynchronousChannelGroup.withThreadPool(Executors.newFixedThreadPool(4));AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(group).bind(new InetSocketAddress("0.0.0.0", 8013));server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {@Overridepublic void completed(AsynchronousSocketChannel result, Void attachment) {server.accept(null, this); // 接受下一个连接try {String now = new Date().toString();ByteBuffer buffer = encoder.encode(CharBuffer.wrap(now + "\r\n"));//result.write(buffer, null, new CompletionHandler<Integer,Void>(){...}); //callback orFuture<Integer> f = result.write(buffer);f.get();System.out.println("sent to client: " + now);result.close();} catch (IOException | InterruptedException | ExecutionException e) {e.printStackTrace();}}@Overridepublic void failed(Throwable exc, Void attachment) {exc.printStackTrace();}});group.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);}
}

Client实现这个例子使用了两种方式。 accept使用了回调的方式, 而发送数据使用了future的方式。

public class Client {public static void main(String[] args) throws Exception {AsynchronousSocketChannel client = AsynchronousSocketChannel.open();Future<Void> future = client.connect(new InetSocketAddress("127.0.0.1", 8013));future.get();ByteBuffer buffer = ByteBuffer.allocate(100);client.read(buffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer result, Void attachment) {System.out.println("client received: " + new String(buffer.array()));}@Overridepublic void failed(Throwable exc, Void attachment) {exc.printStackTrace();try {client.close();} catch (IOException e) {e.printStackTrace();}}});Thread.sleep(10000);}
}

Netty AIO客户端也使用了两种方式, connect使用了future方式,而接收数据使用了回调的方式。

Netty也支持AIO并提供了相应的类: AioEventLoopGroup,AioCompletionHandlerAioServerSocketChannelAioSocketChannel, AioSocketChannelConfig
其它使用方法和NIO类似。

io.netty.buffer和java.nio.ByteBuffer的区别

官方文档Using as a generic library描述了两者的区别,主要还是友好性,扩展和性能的考虑。
http://zizihaier.iteye.com/blog/1767409也提到:

ByteBuffer主要有两个继承的类分别是:HeapByteBuffer和MappedByteBuffer。他们的不同之处在于HeapByteBuffer会在JVM的堆上分配内存资源,而MappedByteBuffer的资源则会由JVM之外的操作系统内核来分配。DirectByteBuffer继承了MappedByteBuffer,采用了直接内存映射的方式,将文件直接映射到虚拟内存,同时减少在内核缓冲区和用户缓冲区之间的调用,尤其在处理大文件方面有很大的性能优势。但是在使用内存映射的时候会造成文件句柄一直被占用而无法删除的情况,网上也有很多介绍。
Netty中使用ChannelBuffer来处理读写,之所以废弃ByteBuffer,官方说法是ChannelBuffer简单易用并且有性能方面的优势。在ChannelBuffer中使用ByteBuffer或者byte[]来存储数据。同样的,ChannelBuffer也提供了几个标记来控制读写并以此取代ByteBuffer的position和limit,分别是:
0 <= readerIndex <= writerIndex <= capacity,同时也有类似于mark的markedReaderIndex和markedWriterIndex。当写入buffer时,writerIndex增加,从buffer中读取数据时readerIndex增加,而不能超过writerIndex。有了这两个变量后,就不用每次写入buffer后调用flip()方法,方便了很多。

Netty的零拷贝(zero copy)

Netty的“零拷贝”主要体现在如下三个方面:

1) Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。
2) Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象,用户可以像操作一个Buffer那样方便的对组合Buffer进行操作,避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer。
3) Netty的文件传输采用了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。

参考

  1. Asynchronous I/O Tricks and Tips
  2. http://openjdk.java.net/projects/nio/resources/AsynchronousIo.html
  3. http://www.ibm.com/developerworks/cn/linux/l-async/
  4. http://www.178linux.com/archives/4811
  5. Netty系列之Netty高性能之道
  6. Is Netty's Zero Copy different from OS level Zero Copy?
  7. Unix Network Programming关于I/O模型的经典介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323189.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P1494-[国家集训队]小Z的袜子【分块优化莫队】

正题 评测记录:https://www.luogu.org/recordnew/lists?uid52918&pidP1494 题目大意 区间任意取两个数&#xff0c;求取到相同的数的概率。 解题思路 假设一个区间有x个y&#xff0c;那么两个都取到y的方案数是x∗(x−1)x*(x-1)x∗(x−1)&#xff0c;那么取到相同总共方…

通过Swashbukle给DotNet Core Web API 增加自动文档功能

DotNet Core Web API给开发者提供了一个很好的框架来开发Restful的API。那么这些API接口该如何管理起来呢&#xff1f;Swagger是一个很好的选择&#xff0c;Swagger不需要开发者额外去维护接口文档&#xff0c;只要开发者的接口遵循Restful的规范&#xff0c;Swagger就会根据AP…

【Python】urllib爬取动漫图片

首先附上需要爬取图片的网站&#xff0c;应该算是个冷门网站&#xff0c;够练手用的了&#xff0c;我的博客图片大部分来自于这里 二次元图片网站 筛选src里的数据 用par r’<img src"[^"].jpg">可以筛选出带有里面的内容 htmldasdas <img src"…

P4137-Rmq Problem/mex【莫队,分块】

正题 评测记录:https://www.luogu.org/recordnew/lists?uid52918&pidP4137 题目大意 求区间mex。 解题思路 开始发现aia_iai​很大&#xff0c;开不了桶。但是转念一想&#xff0c;如果ans>n1ans>n1ans>n1仅当前n1个都有&#xff0c;可是最多只有n个&#xff…

【Python】字符串和变量拼接的写法

我的需求是改变url地址的后缀&#xff0c;其他不改&#xff0c;所以直接for循环&#xff0c;变换数字就行 也就是 字符串变量字符串 想着改变后缀就能批量爬图。但是原本的想法是错误的 for num in range(2,8):url"http://www.win4000.com/wallpaper_detail_160877_"…

Java面试,如何在短时间内做突击

转载自 Java面试&#xff0c;如何在短时间内做突击 面试技术文 Java岗 面试考点精讲&#xff08;基础篇01期&#xff09; Java岗 面试考点精讲&#xff08;基础篇02期&#xff09; Java岗 面试考点精讲&#xff08;网络篇03期&#xff09; Java 面试中遇到的坑 Java面试中…

【学校作业】学生数据打印

数据结构课程布置了一门c语言的结构体作业 要求&#xff1a; 五个学生&#xff0c;数据包括学号&#xff0c;姓名&#xff0c;3门课的成绩&#xff0c;从键盘输入5个学生的数据。打印出3门课总平均成绩&#xff0c;以及最高分 强迫症患者表示打印出的数据必须美观&#xff0c; …

P4879-ycz的妹子【分块】

正题 评测记录:https://www.luogu.org/recordnew/lists?uid52918&pidP4879 题目大意 有若干种操作 Cxy:ax−yC\ x\ y:a_x-yC x y:ax​−yIxy:I\ x\ y:I x y:加一个(原本有的话就改变)axya_xyax​yQ:Q:Q:询问所以数的和Dx:D\ x:D x:删除第xxx个(有的才算)数。 解题思路 …

Entity Framework Core 2.0 使用入门

一.前言 Entity Framework&#xff08;后面简称EF&#xff09;作为微软家的ORM&#xff0c;自然而然从.NET Framework延续到了.NET Core。以前我也嫌弃EF太重而不去使用它&#xff0c;但是EF Core&#xff08;Entity Framework Core&#xff09;已经做了很多性能优化&#xff0…

JavaFX中WebView的java与JS代码互相调用

java代码 package main;import javafx.application.Application; import javafx.beans.value.ObservableValue; import javafx.concurrent.Worker; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.VBox; import javafx.scene.w…

【Python】有效资源爬取并集

由于爬虫代码都不多&#xff0c; 所以我决定在这篇博文上更新所有我觉得比较实用的python代码 方便以后自己调用 环境:python3.7 百度图片爬虫 二次元图片爬取 唐三小说爬取 文件格式命名 百度图片爬虫 百度图片网站 import re import requests from urllib import err…

[编程入门]带参数宏定义练习:定义一个带参的宏,使两个参数的值互换,并写出程序,输入两个数作为使用宏时的实参。输出已交换后的两个值。

#include<bits/stdc.h> #define fun(a,b) ta;ab;bt; using namespace std;int main() {int a,b,t;cin>>a>>b;fun(a,b);cout<<a<<" "<<b;return 0; }

Jexus~docker与它产生了暖味

前段时间写了很多docker for .net core的文章&#xff0c;用来快速部署微服务相当给力&#xff0c;而尝到了香头的我们希望把.net frameworks的程序也使用docker来部署一下&#xff0c;那么接下来我就结果一下&#xff0c;在linux,docker上运行和部署.net frameworks应用程序的…

P3870-[TJOI2009]开关【分块】

正题 解题思路:https://www.luogu.org/recordnew/lists?uid52918&pidP3870 题目大意 n个灯&#xff0c;操作[0,l,r][0,l,r][0,l,r]表示l∼rl\sim rl∼r的灯取反&#xff0c;操作[1,l,r][1,l,r][1,l,r]表示询问l∼rl\sim rl∼r之间有多少灯亮着。 解题思路 分块&#xf…

Linux运维常用检查网络工具

一、Ping ping可以检查网络是否连通&#xff0c;可以很好地帮助我们分析和判定网络故障。 ping ip 二、Telnet telnet通常用来查看某个端口是否可访问。 telnet ip port 三、Curl curl是一个利用URL语法在命令行下工作的文件传输工具&#xff0c;1997年首次发行。它支持…

ABP从入门到精通(1):aspnet-zero-core项目启动及各项目源码说明

一.ABP的简单介绍 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。 ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点&#xff0c;它旨在成为一个通用的WEB应用程序框架和项目模板。 ASP.NET Boilerplate 基于DDD的经典分层架构思想…

[编程入门]宏定义的练习:输入两个整数,求他们相除的余数。用带参的宏来实现,编程序。

#include<bits/stdc.h> #define N a%b; using namespace std;int main() {int a,b;cin>>a>>b;cout<<N;return 0; }

jzoj3518-进化序列(evolve)【位运算】

正题 题目大意 序列aaa 求有多少个数(x,y)(x,y)(x,y)对满足: x<yx<yx<y和axorax1orax2...oray<ma_x\ or\ a_{x1}\ or\ a_{x2}...or\ a_y<max​ or ax1​ or ax2​...or ay​<m 解题思路 首先对于每个y&#xff0c;x满足单调性。 如果(x,y)(x,y)(x,y)可以那…

【Python】Scrapy的安装与使用

scrapy的安装 不得姐网站 直接用命令 pip install scrapy 网络可能较慢&#xff0c;等等就好 另外windows环境下你还需要安装win32 我之前就是因为没有安装这个库&#xff0c;白忙活了一天&#xff0c;一直都是报错状态 pip install pypiwin32 scrapy的使用 cd到卓面或者其他…

[译]ASP.NET Core 2.0 带初始参数的中间件

问题 如何在ASP.NET Core 2.0向中间件传入初始参数&#xff1f; 答案 在一个空项目中&#xff0c;创建一个POCO&#xff08;Plain Old CLR Object&#xff09;来保存中间件所需的参数&#xff1a; public class GreetingOptions { public string GreetAt { get; set; } …