因为网络饱和的可能性,如何在异步框架中高效地写大块的数据是一个特殊的问题。由于写操作是非阻塞的,所以即使没有写出所有的数据,写操作也会在完成时返回并通知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中如何写大型数据的更多相关文章

  1. Netty中的Channel之数据冲刷与线程安全(writeAndFlush)

    本文首发于本博客,如需转载,请申明出处. GitHub项目地址 InChat 一个轻量级.高效率的支持多端(应用与硬件Iot)的异步网络应用通讯框架 前言 本文预设读者已经了解了一定的Netty基础知 ...

  2. js中百分比运算,大型数据会算错

    改法:被除数乘100在做除法运算,就能改掉算错

  3. Netty那点事: 概述, Netty中的buffer, Channel与Pipeline

    Netty那点事(一)概述 Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户ne ...

  4. Netty 中的内存分配浅析-数据容器

    本篇接续前一篇继续讲 Netty 中的内存分配.上一篇 先简单做一下回顾: Netty 为了更高效的管理内存,自己实现了一套内存管理的逻辑,借鉴 jemalloc 的思想实现了一套池化内存管理的思路: ...

  5. CAD在网页中绘图,并为新绘的对象写扩展数据和读取扩展数据

    在网页中绘图,并为新绘的对象写扩展数据和读取扩展数据.下面帮助的完整例子,在控件安装目录的 Sample\Ie\iedemo.htm 中. 主要用到函数说明: _DMxDrawX::InsertBlo ...

  6. 【转】Netty那点事(二)Netty中的buffer

    [原文]https://github.com/code4craft/netty-learning/blob/master/posts/ch2-buffer.md 上一篇文章我们概要介绍了Netty的原 ...

  7. Netty中的连接管理

    连接管理是我们首先需要关注的,检测空闲连接以及超时对于及时释放资源来说是至关重要的.由于这是一项常见的任务,Netty特地为它提供了几个ChannelHandler实现. 用于空闲连接以及超时的Cha ...

  8. Netty中的基本组件及关系

    原文:https://blog.csdn.net/summerZBH123/article/details/79344226---------------------  概述    这篇文章主要是用来 ...

  9. netty中的传输

    终于在课设的闲时间把netty实战的四五章给解决了 这里来记录一下第四章里面所讲的IO 首先说到IO,我想,必须要先了解阻塞,非阻塞,同步和异步这四个词 看到一个讲的很易懂的例子:https://ww ...

随机推荐

  1. VectorDrawable与AnimatedVectorDrawable

    VectorDrawable  Android L开始提供了新的API VectorDrawable 可以使用SVG类型的资源,也就是矢量图.先来一个例子吧. <?xml version=&qu ...

  2. 原生CSS动画回调事件

    原文链接: Detecting CSS Animation Completion with JavaScript 原文日期: 2014年02月20日 翻译日期: 2014年02月21日 翻译人员: 铁 ...

  3. Linux - man page

    使用man date来查看date命令的详细信息. lucifer@lucifer-virtual-machine:~$ man date DATE(1) User Commands DATE(1) ...

  4. 漫谈jdbc

    本文可作为北京尚学堂jdbc课程的学习笔记; 简介 jdbc是什么东西? jdbc全称(Java Database Connectivity java数据库连接) 它是干什么的? 至于它是干什么的,那 ...

  5. Zip操作的工具类

     /** * Copyright 2002-2010 the original author is huanghe. */package com.ucap.web.cm.webapp.util; ...

  6. ”()“和”[]“引发的血案——由此引出C++中关键词new

    先来看一个程序吧: #include <iostream> #include <cassert> using namespace std; int main() { ; int ...

  7. Shell Script - 追踪与debug

    [root@www ~]# sh [-nvx] scripts.sh 选项与参数: -n :不要运行 script,仅查询语法的问题: -v :再运行 sccript 前,先将 scripts 的内容 ...

  8. EBS initialization parameters - Healthcheck

    APPLIES TO: Oracle EBS Applications Performance - Version 11.5.10.2 to 12.2 [Release 11.5.10 to 12.2 ...

  9. CoordinatorLayout

    CoordinatorLayout作为"super-powered FrameLayout"基本实现两个功能:  1.作为顶层布局  2.调度协调子布局 CoordinatorLa ...

  10. myBatis源码之Configuration

    Configuration类主要是用来存储对mybatis的配置文件及mapper文件解析后的数据,Configuration对象会贯穿整个myabtis的执行流程,为mybatis的执行过程提供必要 ...