1. 概述

Netty是JBoss出品的高效的Java NIO开发框架,本文将主要分析Netty实现方面的东西。

Netty总体架构图:

2. Buffer

org.jboss.netty.buffer包的接口及类的结构图如下:

2.1 Channel Buffer的种类

Netty使用ChannelBuffer来存储并操作读写的网络数据。ChannelBuffer除了提供和ByteBuffer类似的方法,还提供了 一些实用方法,具体可参考其API文档。ChannelBuffer的实现类有多个,这里列举其中主要的几个:

  1. HeapChannelBuffer:这是Netty读网络数据时默认使用的ChannelBuffer,这里的Heap就是Java堆的意思,因为读SocketChannel的数据是要经过ByteBuffer的,而ByteBuffer实际操作的就是个byte数组,所以 ChannelBuffer的内部就包含了一个byte数组,使得ByteBuffer和ChannelBuffer之间的转换是零拷贝方式。根据网络字节续的不同,HeapChannelBuffer又分为BigEndianHeapChannelBuffer和 LittleEndianHeapChannelBuffer,默认使用的是BigEndianHeapChannelBuffer。Netty在读网络 数据时使用的就是HeapChannelBuffer,HeapChannelBuffer是个大小固定的buffer,为了不至于分配的Buffer的 大小不太合适,Netty在分配Buffer时会参考上次请求需要的大小。
  2. DynamicChannelBuffer:相比于HeapChannelBuffer,DynamicChannelBuffer可动态自适应大 小。对于在DecodeHandler中的写数据操作,在数据大小未知的情况下,通常使用DynamicChannelBuffer。
  3. ByteBufferBackedChannelBuffer:这是directBuffer,直接封装了ByteBuffer的 directBuffer。

2.2 Buufer的读写策略

对于读写网络数据的buffer,分配策略有两种:

  1. 通常出于简单考虑,直接分配固定大小的buffer,缺点是,对一些应用来说这个大小限制有时是不合理的,并且如果buffer的上限很大也会有内存上的浪费。
  2. 针对固定大小的buffer缺点,就引入动态buffer,动态buffer之于固定 buffer相当于List之于Array。

buffer的寄存策略常见的也有两种(其实是我知道的就限于此):

  1. 在多线程(线程池) 模型下,每个线程维护自己的读写buffer,每次处理新的请求前清空buffer(或者在处理结束后清空),该请求的读写操作都需要在该线程中完成。
  2. buffer和socket绑定而与线程无关。两种方法的目的都是为了重用buffer。

Netty对buffer的处理策略是:读请求数据时,Netty首先读数据到新创建的固定大小的HeapChannelBuffer中,当HeapChannelBuffer满或者没有数据可读 时,调用handler来处理数据,这通常首先触发的是用户自定义的DecodeHandler,因为handler对象是和ChannelSocket 绑定的,所以在DecodeHandler里可以设置ChannelBuffer成员,当解析数据包发现数据不完整时就终止此次处理流程,等下次读事件触发时接着上次的数据继续解析。就这个过程来说,和ChannelSocket绑定的DecodeHandler中的Buffer通常是动态的可重用 Buffer(DynamicChannelBuffer),而在NioWorker中读ChannelSocket中的数据的buffer是临时分配的固定大小的HeapChannelBuffer,这个转换过程是有个字节拷贝行为的。

2.3 ChannelBufferFactory

对ChannelBuffer的创建,Netty内部使用的是ChannelBufferFactory接口,具体的实现有 DirectChannelBufferFactory和HeapChannelBufferFactory。对于开发者创建 ChannelBuffer,可使用实用类ChannelBuffers中的工厂方法。

3. Channel

和Channel相关的接口及类结构图如下:

从该结构图也可以看到,Channel主要提供的功能如下:

  1. 当前Channel的状态信息,比如是打开还是关闭等。
  2. 通过ChannelConfig可以得到的Channel配置信息。
  3. Channel所支持的如read、write、bind、connect等IO操作。
  4. 得到处理该Channel的ChannelPipeline,既而可以调用其做和请求相关的IO操作。

在Channel实现方面,以通常使用的nio socket来说,Netty中的NioServerSocketChannel和NioSocketChannel分别封装了java.nio中包含的 ServerSocketChannel和SocketChannel的功能。

4. ChannelEvent

如前所述,Netty是事件驱动的,其通过ChannelEvent来确定事件流的方向。一个ChannelEvent是依附于Channel的 ChannelPipeline来处理,并由ChannelPipeline调用ChannelHandler来做具体的处理。下面是和 ChannelEvent相关的接口及类图:

对于使用者来说,在ChannelHandler实现类中会使用继承于ChannelEvent的MessageEvent,调用其 getMessage()方法来获得读到的ChannelBuffer或被转化的对象。

4. ChannelPipeline

Netty 在事件处理上,是通过ChannelPipeline来控制事件流,通过调用注册其上的一系列ChannelHandler来处理事件,这也是典型的拦截 器模式。下面是和ChannelPipeline相关的接口及类图:

事件流有两种,upstream事件和downstream事件。在ChannelPipeline中,其可被注册的ChannelHandler既可以 是 ChannelUpstreamHandler 也可以是ChannelDownstreamHandler ,但事件在ChannelPipeline传递过程中只会调用匹配流的ChannelHandler。在事件流的过滤器链 中,ChannelUpstreamHandler或ChannelDownstreamHandler既可以终止流程,也可以通过调用 ChannelHandlerContext.sendUpstream(ChannelEvent)或 ChannelHandlerContext.sendDownstream(ChannelEvent)将事件传递下去。下面是事件流处理的图示:

从上图可见,upstream event是被Upstream Handler们自底向上逐个处理,downstream event是被Downstream Handler们自顶向下逐个处理,这里的上下关系就是向ChannelPipeline里添加Handler的先后顺序关系。简单的理 解,upstream event是处理来自外部的请求的过程,而downstream event是处理向外发送请求的过程。

服务端处 理请求的过程通常就是解码请求、业务逻辑处理、编码响应,构建的ChannelPipeline也就类似下面的代码片断

4.1 ChannelPipeline中编码解码Handler

ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new MyProtocolDecoder());
pipeline.addLast("encoder", new MyProtocolEncoder());
pipeline.addLast("handler", new MyBusinessLogicHandler());

其中,MyProtocolDecoder是ChannelUpstreamHandler类型,MyProtocolEncoder是 ChannelDownstreamHandler类型,MyBusinessLogicHandler既可以是 ChannelUpstreamHandler类型,也可兼ChannelDownstreamHandler类型,视其是服务端程序还是客户端程序以及 应用需要而定。

补充一点,Netty对抽象和实现做了很好的解耦。像org.jboss.netty.channel.socket包, 定义了一些和socket处理相关的接口,而org.jboss.netty.channel.socket.nio、 org.jboss.netty.channel.socket.oio等包,则是和协议相关的实现。

5. codec framework

对于请求协议的编码解码,当然是可以按照协议格式自己操作ChannelBuffer中的字节数据。另一方面,Netty也做了几个很实用的codec helper,这里给出简单的介绍。

  1. FrameDecoder:FrameDecoder内部维护了一个 DynamicChannelBuffer成员来存储接收到的数据,它就像个抽象模板,把整个解码过程模板写好了,其子类只需实现decode函数即可。 FrameDecoder的直接实现类有两个:(1)DelimiterBasedFrameDecoder是基于分割符 (比如\r\n)的解码器,可在构造函数中指定分割符。(2)LengthFieldBasedFrameDecoder是基于长度字段的解码器。如果协 议 格式类似“内容长度”+内容、“固定头”+“内容长度”+动态内容这样的格式,就可以使用该解码器,其使用方法在API DOC上详尽的解释。
  2. ReplayingDecoder: 它是FrameDecoder的一个变种子类,它相对于FrameDecoder是非阻塞解码。也就是说,使用 FrameDecoder时需要考虑到读到的数据有可能是不完整的,而使用ReplayingDecoder就可以假定读到了全部的数据。
  3. ObjectEncoder 和ObjectDecoder:编码解码序列化的Java对象。
  4. HttpRequestEncoder和 HttpRequestDecoder:http协议处理。

Netty详解(四):Netty 整体架构相关推荐

  1. 详解MRS CDL整体架构设计

    摘要:MRS CDL是FusionInsight MRS推出的一种数据实时同步服务,旨在将传统OLTP数据库中的事件信息捕捉并实时推送到大数据产品中去,本文档会详细为大家介绍CDL的整体架构以及关键技 ...

  2. Netty详解(持续更新中)

    Netty详解 1. Netty概述 1.1 Netty简介 1.2 原生NIO问题 1.3 Netty特点 1.4 Netty应用场景 1.3 Netty版本说明 2. Java IO模型 2.1 ...

  3. 第43课: Spark 1.6 RPC内幕解密:运行机制、源码详解、Netty与Akka等

    第43课: Spark 1.6 RPC内幕解密:运行机制.源码详解.Netty与Akka等 Spark 1.6推出了以RpcEnv.RPCEndpoint.RPCEndpointRef为核心的新型架构 ...

  4. VIP 时代,详解会员营销系统架构技术实践!

    作者| 阿里文娱高级开发工程师  臻龙 责编 | 屠敏 头图 | CSDN 下载自视觉中国 背景介绍 随着在线视频行业数十年的发展,各家的会员业务,尤其是会员规模都已进入成熟期,呈现饱和状态.会员营销 ...

  5. java实现的微服务架构_详解Java 微服务架构

    一.传统的整体式架构 传统的整体式架构都是模块化的设计逻辑,如展示(Views).应用程序逻辑(Controller).业务逻辑(Service)和数据访问对象(Dao),程序在编写完成后被打包部署为 ...

  6. linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)(列集散集函数)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  7. Android Studio 插件开发详解四:填坑

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78265540 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

  8. springboot 详解 (四)redis filter

    ---------------------------------------------------------------------------------------------------- ...

  9. 数据结构--图(Graph)详解(四)

    数据结构–图(Graph)详解(四) 文章目录 数据结构--图(Graph)详解(四) 一.图中几个NB的算法 1.普里姆算法(Prim算法)求最小生成树 2.克鲁斯卡尔算法(Kruskal算法)求最 ...

  10. .NET DLL 保护措施详解(四)各操作系统运行情况

    我准备了WEB应用程序及WinForm应用程序,分别在WIN SERVER 2012/2008/2003.Win7/10上实测,以下为实测结果截图: 2012 2008 2003 WIN7 WIN10 ...

最新文章

  1. asp.net模版页面的高级应用
  2. Git for Windows 2.13.1(2) 发布,分布式版本控制系统
  3. Java设计模式10:观察者模式
  4. java2ee和java2se_Java知识:(2)JavaSE和JavaEE
  5. 牛客题霸 转圈打印矩阵 C++题解/答案
  6. 调用接口返回500_公交卡余额查询接口开放使用啦!
  7. cad直线和圆弧倒角不相切_曲线操作-直线,圆弧,圆,倒斜角
  8. linux脚本expect分区,linux – 从不同位置执行Expect脚本
  9. Android7.1+查看audio policy使用.conf/.xml(二十七)
  10. 图像局部特征(十六)--SimpleBlobDetector
  11. 决策树C4.5算法对ID3算法的改进
  12. lammps教程:薄膜渗透过滤模拟--平衡弛豫过程
  13. stm32 带通滤波器_【安富莱——DSP教程】第37章 FIR滤波器的实现
  14. java导出可运行文件格式,|java导出excel,excel打不开,报文件格式无效,怎么解决!...
  15. 高速工业相机应用领域
  16. C# 处理PPT水印(三)—— 在PPT中添加多行(平铺)文本水印效果
  17. 大数据分析应用领域之预测性分析
  18. 嵌入式Linux开发_Ping来Ping去
  19. IOT数字世界价值论(下)
  20. 程序员 coding啥意思_使用Coding4Fun DevKit的vCard预览处理程序

热门文章

  1. 实战:向GitHub提交代码时触发Jenkins自动构建
  2. iOS7与iOS8的比較
  3. MySQL执行外部sql脚本
  4. 如何在XSLT里调用C#的代码
  5. (转)SQL操作全集
  6. 毕业以来,今天第一次领到工资,好兴奋哪
  7. 移动芯片领域变天?苹果宣布重大决定,芯片霸主市值一夜蒸发近千亿
  8. Facebook开源算法代码库,轻松复现前沿视频理解模型
  9. OpenCV计算机视觉编程攻略之生成椒盐噪声实现
  10. c++程序员会用到的函数积累