`
zizihaier
  • 浏览: 55364 次
  • 性别: Icon_minigender_2
  • 来自: 成都
社区版块
存档分类
最新评论

NIO buffer和netty buffer

    博客分类:
  • java
 
阅读更多
NIO中的Buffer
   前面提到过,在NIO中同样存在一个缓冲区,叫做ByteBuffer,来配合Channel的使用。在ByteBuffer内部存储数据的实质为一个字节数组,如:final byte[] hb,并定义了四个标记来管理它。其中包括:mark <= position <= limit <= capacity。其中capacity用来表示缓冲区的大小;position用来标识下一个可读取或者写入的位置;limit表示读取或者写入的上限位置,如果要在>=limit的位置做读写操作会抛出异常;mark用来记录当前position的值,记录之后position随着读写发生变化,在调用reset()方法时,会将position恢复为mark记录的值。在buffer中提供了很多put、get方法来放入和读取数据,这里不多做介绍,可以查看API。但其中有几个重要的方法需要关注:
1.  flip()方法:在读取或者写入n个字节(position + n < limit)后,position += n。如果是先读取数据到buffer后写入到Channel,必须将position的值回退到起初的值,并且将limit设置为有效位置,才能让读入的数据真正的写入Channel。调用flip()方法后,buffer中的四个标记会发生以下变化:

Java代码 
limit = position; 
position = 0; 
mark = -1; 

2.  clear()方法:同样的,将buffer中的数据写入Channel后,再读取一些数据到buffer中,此时往往需要将各标记的值归位,当做一个新的buffer来使用(当然也有特殊情况)。调用clear()方法后,标记变化如下:

Java代码 
position = 0; 
limit = capacity; 
mark = -1; 

3.  rewind()方法:如果发现刚才从Channel读取的数据需要重新读取,可以调用该方法。调用后标记变化如下:

Java代码 
position = 0; 
mark = -1; 
  尤其是flip()和clear()方法,在使用的过程中会频繁用到,否则会造成读取和写入的错乱。
  ByteBuffer主要有两个继承的类分别是:HeapByteBuffer和MappedByteBuffer。他们的不同之处在于HeapByteBuffer会在JVM的堆上分配内存资源,而MappedByteBuffer的资源则会由JVM之外的操作系统内核来分配。DirectByteBuffer继承了MappedByteBuffer,采用了直接内存映射的方式,将文件直接映射到虚拟内存,同时减少在内核缓冲区和用户缓冲区之间的调用,尤其在处理大文件方面有很大的性能优势。但是在使用内存映射的时候会造成文件句柄一直被占用而无法删除的情况,网上也有很多介绍。

Netty中的Buffer
   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()方法,方便了很多。

   在ChannelBuffer中有几个重要的类继承,AbstractChannelBuffer中实现了基本的方法;HeapChannelBuffer是对NIO中heapBuffer的封装,它有两个继承类:BigEndianHeapChannelBuffer和LittleEndianHeapChannelBuffer(试想,我们将一个int类型(32位)的数据放入内存中,内存会以什么样的顺序放入这32位的数据呢?这就分为big-endian和little-endian的字节序,big-endian就是说将数据的高位放在内存地址更小的位置,little-endian是将低位放在内存地址更小的位置,选择和所用硬件和操作系统相同的字节序有利于提高性能);ByteBufferBackedChannelBuffer是对NIO中derectBuffer的封装;DynamicChannelBuffer继承于AbstractChannelBuffer,实现了buffer的自动扩容;CompositeChannelBuffer也是继承于AbstractChannelBuffer,抽象了操作多个buffer的情况,将多个buffer有序的放入数组中,通过计算找出要操作的buffer的下标,而不是将多个buffer复制到一个更大的buffer中;实现WrappedChannelBuffer接口的类主要是对buffer进行进一步的包装,一般由netty框架内部调用;ReplayingDecoderBuffer用于封装了解码时常有的处理,配合ReplayDecoder使用,后面会对编码解码做专门研究。
  ChannelBuffer往往由BufferFactory或者ChannelBuffers类来创建实例。
  回到本实例,netty在读取到客户端的msg时,根据用户配置的BufferFactory的不同会将消息封装成derectBuffer或者heapBuffer。所以,当我们在接收数据时,pipline中第一个upstreamHandler拿到的msg(e.getMessage())虽然是Object类型,但是肯定是这两种形式的buffer。那么,我们在写回数据的时候能不能直接使用其他类型呢,答案是:pipline中第一个downstreamHandler不能随意的放入其他对象,原因是pipline中downstream事件是从tail端往上执行的,所以第一个downstreamHandler调用的channel.write()或者channels.write()方法传入的object会直接传递给netty底层处理,而在netty的写入出口中,只接收两种类型的对象:ChannelBuffer和FileRegion(FileRegion可用于0-copy的文件传输,一般情况下,应用程序向socket发送文件流时,操作系统需要先将文件的字节流存储到内核缓冲区(file_read_buffer),然后拷贝到用户缓冲区,在由用户缓冲区拷贝到内核缓冲区(socket_buffer)由协议引擎发送。这样会创建四个缓冲区,两次复制的过程。所谓零拷贝是指:内核通过DMA引擎,直接将file_read_buffer的数据copy到socket_buffer中,而在后面的改进中废除了复制的操作,给socket_buffer增加了数据的位置和长度信息描述,直接将数据从file_read_buffer传递给协议引擎。在netty中只有选择NIO模型才能支持0-copy,当然JDK版本或者操作系统不支持也是不行的)。所以本实例先将字符串”success”方法放入到ChannelBuffer中,然后在调用write方法。
Channels为我们提供了很多方法用于向上或者向下传递事件,对应于概念篇中讲到的各种事件。其中以fire开头方法用于upstream事件,而例如write这样的方法主要用于downstream事件。而这些方法往往是成对出现的,例如:fireChannelOpen(Channel channel)、fireChannelOpen(ChannelHandlerContext ctx)等,由于这两个方法有不同的参数,造成了流程的不同,如果参数是Channel,则整个流程会从pipline的head upstreamHandler开始重新执行,如果参数是ChannelHandlerContext,则会直接执行下一个upstreamHandler。同样,write(Channel channel, Object message)、write(ChannelHandlerContext ctx, ChannelFuture future, Object message)等方法,出了多了一个future外,和前面的两个方法相同,流程也会相同,如果没有传入ChannelFuture,则会在方法中的第一步中创建一个future来支持netty的异步事件处理机制。
分享到:
评论

相关推荐

    jack netty 5,适用与android和服务器.rar

    换句话说,Netty是一个NIO框架,使用它可以简单快速地开发网络应用程序,比如客户端和服务端的协议。Netty大大简化了网络程序的开发过程比如TCP和UDP的 Socket的开发。 "快速和简单"并不意味着应用程序会有难维护...

    精通并发与netty视频教程(2018)视频教程

    48_Netty与NIO系统总结及NIO与Netty之间的关联关系分析 49_零拷贝深入剖析及用户空间与内核空间切换方式 50_零拷贝实例深度剖析 51_NIO零拷贝彻底分析与Gather操作在零拷贝中的作用详解 52_NioEventLoopGroup源码...

    精通并发与netty 无加密视频

    第48讲:Netty与NIO系统总结及NIO与Netty之间的关联关系分析 第49讲:零拷贝深入剖析及用户空间与内核空间切换方式 第50讲:零拷贝实例深度剖析 第51讲:NIO零拷贝彻底分析与Gather操作在零拷贝中的作用详解 第...

    精通并发与 netty 视频教程(2018)视频教程

    76_Netty项目开发过程中常见且重要事项分析 77_Java NIO Buffer总结回顾与难点拓展 78_Netty数据容器ByteBuf底层数据结构深度剖析 79_Netty的ByteBuf底层实现大揭秘 80_Netty复合缓冲区详解与3种缓冲区适用场景分析 ...

    Netty应用说明笔记

    例如前两者并没有提供针对 Protocol Buffer、JSON这些信息格式的封装,但是Netty框架提供了这些数据格式封装(基于责任链模式的编码和解码功能); 2、直接使用NIO需要需要额外的技能,例如Java多线程,网络编程; 3...

    Netty由浅到深_第三章_NIO模型3大组件详细介绍

    数据的读写是通过Buffer,这个和BIO不同的。BIO中要么是输入流或者是输出流,不可能是双向流动的,但是NIO中的Buffer是可以读也可以写,需要用flip()方法切换 channel是双向的,可以返回底层操作系统情况,比如...

    java8源码-netty-learn:这是一个用于netty学习的工程

    ##NIO基础 三大组件 Channel & Buffer channel有点类似于stream,它就是读写数据的双向通道,可以从channel将数据读入buffer,也可以将buffer中的数据写入到channel 中,而stream只能完成一种 常见的Channel有 ...

    互联网大厂Netty网络编程开发三部曲-Netty优化+进阶+ 入门 Netty协议设计与解析

    ├─(1) 第1章_01_nio三大组件-channel-buffer.mp4 ├─(2) 第1章_02_nio三大组件-服务器设计-多线程版.mp4 ├─(3) 第1章_03_nio三大组件-服务器设计-线程池版.mp4 ├─(4) 第1章_04_nio三大组件-服务器设计-...

    一文看懂 Netty 架构设计.docx

    它由一系列辅助类完成,包括 Reactor 线程 NioEventLoop 及其父类,NioSocketChannel / NioServerSocketChannel 及其父类,Buffer 组件,Unsafe 组件 等。该层的主要职责就是监听网络的读写和连接操作,负责将网络层...

    Spark的shuffle调优

    spark.shuffle.blockTransferService netty shuffle过程中,传输数据的方式,两种选项,netty或nio,spark 1.2开始,默认就是netty,比较简单而且性能较高,spark 1.5开始nio就是过期的了,而且spark 1.6中会去除掉 ...

    Mina 文档doc

    • Multipurpose Infrastructure for Network Applications • 一个基于非阻塞I/O的网络框架。...如果你使用MINA,你将不需要直接使用NIO buffers,因为仅使用MINA buffers就可以完成大多数buffer操作

    elasticsearch-5.1.1客户端JAVA开发需要的52个jar包

    lucene-suggest-6.3.0.jar,netty-3.10.6.Final.jar,netty-buffer-4.1.6.Final.jar,netty-codec-4.1.6.Final.jar,netty-codec-http-4.1.6.Final.jar,netty-common-4.1.6.Final.jar,netty-handler-4.1.6.Final.jar,...

    com.yangc.hub:基于Netty的消息推送服务器实现

    com.yangc.hub基于Netty的初级推送服务器实现Netty - 强大的网络应用程序框架,封装了java nio,基于事件驱动的异步api。ActiveMQ - apache的一款消息服务器,这里主要用于多台推送服务器间进行消息传送,达到负载...

    elasticsearch-5.2.2客户端JAVA开发需要的69个jar包

    6.4.1.jar,lucene-spatial3d-6.4.1.jar,lucene-suggest-6.4.1.jar,netty-3.10.6.Final.jar,netty-buffer-4.1.7.Final.jar,netty-codec-4.1.7.Final.jar,netty-codec-http-4.1.7.Final.jar,netty-common-4.1.7.Final....

    JAVA上百实例源码以及开源项目源代码

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

    JAVA上百实例源码以及开源项目

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

Global site tag (gtag.js) - Google Analytics