Netty中如何写大型数据
因为网络饱和的可能性,如何在异步框架中高效地写大块的数据是一个特殊的问题。由于写操作是非阻塞的,所以即使没有写出所有的数据,写操作也会在完成时返回并通知ChannelFuture。当这种情况发生时,如果仍然不停地写入,就有内存耗尽的风险。所以在写大型数据时,需要准备好处理到远程节点的连接是慢速连接的情况,这种情况会导致内存释放的延迟。让我们考虑下将一个文件内容写出到网络的情况。
我们知道在传输的过程中,由于NIO的零拷贝特性,这种特性消除了将文件的内容从文件系统移动到网络栈的复制过程。所有的这一切都发生在Netty的核心中,所以应用程序所有需要做的就是使用一个FileRegion接口的实现,其在Netty的API文档中的定义是:“通过支持零拷贝的文件传输的Channel来发送的文件区域。”
下面的代码清单展示了如何通过从FileInputStream创建一个DefaultFileRegion,并将其写入Channel,从而利用零拷贝特性来传输一个文件的内容。
使用FileRegion传输文件的内容
FileInputStream in = new FileInputStream(file); // 创建一个FileInputStream
FileRegion region = new DefaultFileRegion(in.getChannel(), 0, // 以该文件的完整长度创建一个新的DefaultFileRegion
file.length());channel.writeAndFlush(region).addListener(// 发送该DefaultFileRegion,并注册一个ChannelFutureListener new ChannelFutureListener(){ @Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
Throwable cause = future.cause();// 处理失败
// Do something
}
} });
这个示例只适用于文件内容的直接传输,不包括应用程序对数据的任何处理。在需要将数据从文件系统复制到用户内存中时,可以使用ChunkedWriteHandler,它支持异步写大型数据流,而又不会导致大量的内存消耗。
关键是interfaceChunkedInput<B>,其中类型参数B是readChunk()方法返回的类型。Netty预置了该接口的4个实现,如下表中所列出的。每个都代表了一个将由ChunkedWriteHandler处理的不定长度的数据流。
ChunkedInput 的实现
ChunkedFile 从文件中逐块获取数据,当你的平台不支持零拷贝或者你需要转换数据时使用
ChunkedNioFile 和ChunkedFile 类似,只是它使用了FileChannel
ChunkedStream 从InputStream 中逐块传输内容
ChunkedNioStream 从ReadableByteChannel 中逐块传输内容
下面代码清单说明了ChunkedStream的用法,它是实践中最常用的实现。所示的类使用了一个File以及一个SslContext进行实例化。当initChannel()方法被调用时,它将使用所示的ChannelHandler 链初始化该Channel。
当Channel 的状态变为活动的时,WriteStreamHandler 将会逐块地把来自文件中的数据作为ChunkedStream 写入。数据在传输之前将会由SslHandler加密。
使用ChunkedStream 传输文件内容
public class ChunkedWriteHandlerInitializer extends ChannelInitializer<Channel> {
private final File file;
private final SslContext sslCtx;
public ChunkedWriteHandlerInitializer(File file, SslContext sslCtx) {
this.file = file;
this.sslCtx = sslCtx;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new SslHandler(sslCtx.newEngine(ch.alloc());// 将SslHandler添加到ChannelPipeline中
pipeline.addLast(new ChunkedWriteHandler());// 添加ChunkedWriteHandler以处理作为ChunkedInput传入的数据
pipeline.addLast(new WriteStreamHandler());// 一旦连接建立,WriteStreamHandler就开始写文件数据
}
public final class WriteStreamHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {// 当连接建立时,channelActive()方法将使用ChunkedInput写文件数据
super.channelActive(ctx);
ctx.writeAndFlush(new ChunkedStream(new FileInputStream(file)));
}
}
}
逐块输入要使用你自己的ChunkedInput实现,请在ChannelPipeline中安装一个ChunkedWriteHandler。在本节中,我们讨论了如何通过使用零拷贝特性来高效地传输文件,以及如何通过使用ChunkedWriteHandler来写大型数据而又不必冒着导致OutOfMemoryError的风险。
Netty中如何写大型数据的更多相关文章
- Netty中的Channel之数据冲刷与线程安全(writeAndFlush)
本文首发于本博客,如需转载,请申明出处. GitHub项目地址 InChat 一个轻量级.高效率的支持多端(应用与硬件Iot)的异步网络应用通讯框架 前言 本文预设读者已经了解了一定的Netty基础知 ...
- js中百分比运算,大型数据会算错
改法:被除数乘100在做除法运算,就能改掉算错
- Netty那点事: 概述, Netty中的buffer, Channel与Pipeline
Netty那点事(一)概述 Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户ne ...
- Netty 中的内存分配浅析-数据容器
本篇接续前一篇继续讲 Netty 中的内存分配.上一篇 先简单做一下回顾: Netty 为了更高效的管理内存,自己实现了一套内存管理的逻辑,借鉴 jemalloc 的思想实现了一套池化内存管理的思路: ...
- CAD在网页中绘图,并为新绘的对象写扩展数据和读取扩展数据
在网页中绘图,并为新绘的对象写扩展数据和读取扩展数据.下面帮助的完整例子,在控件安装目录的 Sample\Ie\iedemo.htm 中. 主要用到函数说明: _DMxDrawX::InsertBlo ...
- 【转】Netty那点事(二)Netty中的buffer
[原文]https://github.com/code4craft/netty-learning/blob/master/posts/ch2-buffer.md 上一篇文章我们概要介绍了Netty的原 ...
- Netty中的连接管理
连接管理是我们首先需要关注的,检测空闲连接以及超时对于及时释放资源来说是至关重要的.由于这是一项常见的任务,Netty特地为它提供了几个ChannelHandler实现. 用于空闲连接以及超时的Cha ...
- Netty中的基本组件及关系
原文:https://blog.csdn.net/summerZBH123/article/details/79344226--------------------- 概述 这篇文章主要是用来 ...
- netty中的传输
终于在课设的闲时间把netty实战的四五章给解决了 这里来记录一下第四章里面所讲的IO 首先说到IO,我想,必须要先了解阻塞,非阻塞,同步和异步这四个词 看到一个讲的很易懂的例子:https://ww ...
随机推荐
- JavaScript检测提交表单text合法
近日,一朋友开设了地方性质的论坛,让我帮他处理下Login.php(所谓的用户的登陆页面),但是登陆的时候,出现空字符或敏感字符,需要提交到服务端的Script处理,大大降低了效率,于是乎,就有了此代 ...
- Java泛型和通配符那点事
泛型(Generic type 或者generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法 ...
- Linux进程管理(第二版) --进程管理命令
进程管理命令 一.查看用户信息.5.15 分钟内的系统的,优先值越小,优先权越大 ] 1.nice 指定程序运行的优先级 格式 nice -n command 例如 nice -5 myprogrem ...
- plsql 导入导出表、数据、序列、视图
一.导出: 1.打开plsql-->工具---->导出用户对象(可以导出表结构和序列.视图) ps:如果上面不选中"包括所有者",这样到导出的表结构等就不包含所有 ...
- Aandroid 图片加载库Glide 实战(一),初始,加载进阶到实践
原文: http://blog.csdn.net/sk719887916/article/details/39989293 skay 初识Glide 为何使用 Glide? 有经验的 Android ...
- AndroidUI之绘图机制和原理 最完整的文章
转载请标明出处:http://blog.csdn.net/sk719887916/article/details/39961171,作者:skay 导读: 熟悉javaGUI的朋友对java绘图必定 ...
- 基于Bresenham和DDA算法画线段
直线:y=kx+b 为了将他在显示屏上显示出来,我们需要为相应的点赋值,那么考虑到计算机的乘法执行效率,我们肯定不会选择用Y=kx+b这个表达式求值,然后进行画线段. 我们应当是将它转化为加法运算. ...
- javascript中的eval函数
eval()只有一个参数,如果传入的参数不是字符串,则直接返回这个参数.否则会将字符串当成js代码进行编译,如果编译失败则抛出语法错误(SyntaxError)异常.如果编译成功则开始执行这段代码,并 ...
- JAVA线程与线程、进程与进程间通信
I.线程与线程间通信 一.基本概念以及线程与进程之间的区别联系: 关于进程和线程,首先从定义上理解就有所不同1.进程是什么?是具有一定独立功能的程序.它是系统进行资源分配和调度的一个独立单位,重点在系 ...
- 大数据小视角1:从行存储到RCFile
前段时间一直在忙碌写毕设与项目的事情,很久没有写一些学习心得与工作记录了,开了一个新的坑,希望能继续坚持写作与记录分布式存储相关的知识.为什么叫小视角呢?因为属于随想型的内容,可能一个由小的视角来审视 ...