`
zizihaier
  • 浏览: 56641 次
  • 性别: 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的异步事件处理机制。
分享到:
评论

相关推荐

    【项目实战】Netty源码剖析&NIO;+Netty5各种RPC架构实战演练三部曲视频教程(未加密)

    NIO主要由Buffer、Channel、Selector三大组件构成,其中Selector用于多路复用I/O操作。 #### 三、Netty源码剖析 ##### 1. Netty架构设计 - **Bootstrap**:启动客户端和服务端的应用程序。 - **Channel**:代表...

    详细介绍 NIO与Netty编程-实战讲义详细pdf.7z

    它提供了丰富的API,简化了NIO的复杂性,如缓冲区(Buffer)、管道(ChannelHandlerContext)和处理器链(ChannelPipeline)。Netty还支持多种传输类型,如TCP、UDP以及HTTP、WebSocket等协议,使得构建复杂的网络...

    Java_NIO框架Netty教程.pdf

    学习Netty,需要掌握Java NIO的基本概念,如选择器(Selector)、通道(Channel)、缓冲区(Buffer)等,以及Netty框架的使用和设计模式。通过阅读"Java NIO框架Netty教程.pdf",你可以深入理解Netty的工作原理,并...

    自己手写nio和netty,不建议下载

    NIO的核心在于通道(Channel)和缓冲区(Buffer),它允许程序以非阻塞的方式读写数据,提高了处理大量并发连接的能力,特别适用于服务器端编程。 在传统的Java I/O模型中,I/O操作是基于流(Stream)的,数据从一...

    基于netty的nio使用demo源码

    5. **数据交换**:在连接建立后,数据的读写操作会在NIO的Buffer和Handler之间进行。Netty提供了一种方便的方式来处理这些操作,例如,使用read()方法从通道读取数据到缓冲区,然后通过处理器链进行解码;反之,使用...

    NIO Netty框架

    NIO(Non-blocking I/O)框架是一种高性能的I/O模型,Netty和Mina都是基于NIO的框架。Netty和Mina都是Java开发的高性能网络框架,供开发者快速构建高性能的网络应用程序。下面是关于Netty和Mina的详细知识点: 开发...

    基于JAVA IO, NIO, Netty, 多线程并发实战源码.zip

    NIO的核心组件包括Channel、Buffer和Selector。Channel类似于流,但支持双向数据传输。Buffer用于存储数据,而Selector则允许单个线程监视多个通道的事件,提高了并发性能。NIO在处理大量连接和大文件时效率较高,...

    nio、bio、netty的一些案例

    然而,NIO的编程模型相对复杂,需要处理更多的细节,如缓冲区(Buffer)管理和读写操作。 Netty是一个高性能、异步事件驱动的网络应用框架,它基于NIO构建,但提供了更高级别的抽象,简化了网络编程。Netty的反应器...

    基于Java NIO的网络服务器Netty生产实例.zip

    1. **Java NIO基础**:NIO的核心组件包括Channel(通道)、Buffer(缓冲区)和Selector(选择器)。Channel是数据传输的通道,支持双向传输;Buffer用于存储数据,提供了更高效的数据读写操作;Selector允许单线程...

    BIO,NIO,AIO,Netty面试题

    2. 解释Java NIO中的Channel、Buffer、Selector各自的角色和功能。 3. AIO如何实现异步I/O,与NIO相比有何优势。 4. Netty的核心特性,如事件驱动模型、处理器链、零拷贝等。 5. 实际项目中,如何选择合适的I/O模型...

    学习juc、nio、netty、tomcat调优、jvm调优-Advanced-JAVA.zip

    NIO的核心组件包括通道(Channel)、缓冲区(Buffer)和选择器(Selector)。通过NIO,开发者可以在单个线程中处理多个连接,极大地提高了服务器的并发能力。 3. **Netty框架** Netty是一个高性能、异步事件驱动的...

    NIO学习-Java源代码分享(含netty)

    NIO的核心组件包括Channel、Buffer和Selector,它们共同构建了一个非阻塞的I/O模型。 1. **Channel**:在NIO中,数据通过Channel进行传输。Channel类似于传统I/O中的流,但它可以同时读写,并且是双向的。常见的...

    Netty权威指南高清版本

    书中会介绍Channel、Selector、Buffer等NIO核心组件,并展示如何在Netty中使用它们。 接着,书中会深入讲解Netty的EventLoop和EventLoopGroup。EventLoop是Netty中的工作线程,负责处理I/O事件和执行用户定义的任务...

    深入浅出Netty_netty_

    此外,Netty的ByteBuf是高效的数据缓冲区,提供了比Java NIO Buffer更友好的API。它支持预读和后写,可以在不复制数据的情况下进行读写操作,从而提高了性能。 书中的代码案例会涵盖如何创建服务器、建立连接、处理...

    netty 新NIO框架 文档

    - **Google Protocol Buffer集成**:为了满足高性能序列化的需求,Netty还集成了Google的Protocol Buffer库,进一步提升了数据处理的速度。 #### 四、入门示例详解 ##### 4.1 编写丢弃服务器 Netty提供了快速搭建...

    Netty那点事(2)Netty中的bufferJava开

    本文将深入探讨Netty中的Buffer组件,这是Netty处理网络数据的核心部分,对于理解和优化Java应用的性能至关重要。 Netty中的Buffer,即ByteBuf,是Netty自定义的一种内存管理机制,它取代了Java NIO中的ByteBuffer...

    JAVA知识图谱:JVM、JMM、JUC、NIO、Netty、IOC、AOP、Jav-JavaKnowledge.zip

    NIO的核心组件包括Selector、Channel和Buffer,它们提供了异步I/O操作,适用于高并发的网络应用。 **5. Netty** Netty是一个高性能、异步事件驱动的网络应用框架,用于快速开发可维护的高性能协议服务器和客户端。...

Global site tag (gtag.js) - Google Analytics