io.netty.channel.ChannelPipeline
 
设计原理

  

  上图中,为了更直观地展示事件处理顺序, 故意有规律地放置两种handler的顺序,实际上ChannelInboundHandler和ChanneOutboundHandler的顺序可以是任意,取决于用户调用add方法把handler方在哪里。
 
  ChannelPipeline的特性:
  1. 它是一个双向链表
  2. 每个节点持有一个ChannelHandler实例,这个实例可以是ChannelInboundHandler类型或ChannelOutboundHandler类型,
  3. ChannelInboundHandler类型的handler只处理inbound事件,ChannelInboundHandler只处理outbound事件。
  4. inbound事件处理顺序是由链表头到链表尾,outbound事件的处理顺序是由链表尾到链表头。
  5. inbound事件由netty内部触发,最终由netty外部的代码消费。outbound事件由netty外部的代码触发,最终由netty内部消费。
 
接口设计
  ChannelPipeline接口定义的方法分为三种类型:链表管理的方法、触发outbound事件的方法、触发inbound事件的方法。
 
链表管理的方法
添加:addFirst, addLast, addAfter, addBefore。
删除:removeFirst, removeLast, remove。
替换:replace。
查找:first, last, get。
 
触发outbound事件的方法
bind(SocketAddress, ChannelPromise)
connect(SocketAddress, SocketAddress, ChannelPromise)
write(Object, ChannelPromise)
flush()
read()
disconnect(ChannelPromise)
close(ChannelPromise)
deregister(ChannelPromise)
 
触发inbound事件的方法
fireChannelRegistered()
fireChannelActive()
fireChannelRead(Object)
fireChannelReadComplete()
fireExceptionCaught(Throwable)
fireUserEventTriggered(Object)
fireChannelWritabilityChanged()
fireChannelInactive()
fireChannelUnregistered()
 
 
 
Channel,EventLoop,ChannelPipeline,EventExecutor和ChannelHandler之间的关系
  每个channel持有一个eventLoop, channel.unsafe的方法会在这个eventLoop中执行。那么问题来了,使用add方法向channelPiple中添加一个channelHandler,这个handler的方法在哪里执行呢?下面以addLast为例看看添加方法。
ChannelPipeline addLast(ChannelHandler... handlers)
ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers)
ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler)
 
  channelPiple负责为每个新添加的handler分配一个eventExecutor。如果你调用了带grop参数的方法添加handler ,channelPiple会从group中取出一个eventExecutor分配给这个handler, 这时handler中的回调方法会在这个eventExecutor线程中执行,否则channelPiple会把channel的eventLoop当成eventExecutor分配给这个handler,这时这个handler的回调方法会在eventLoop的线程中执行。这个两者有什么不同呢?如果没你没有给handler指定group,它将会和channel的I/O操作共享线程资源,它能得到多少线程资源取决于eventLoop的ioRatio属性的设置,执行时间过长的handler的回调方法会影响I/O操作。如果指定了group,handler的回调方法和channel的I/O操作将会被隔离到不同的线程中。在高并发情况下,强烈建议为不同功能的handler指定不同的group。
每个channel实例在创建的时候,它自己负责创建一个channelPiple实例。随后这个channel会被注册到一个eventLoop中,eventLoop负责处理channel上触发的I/O事件,把I/O事件转换成对channel.unsafe方法的调用。unsafe负责做实际的I/O操作,根据需要调用channelPiple触发事件。channelPiple依次调用合适的handler处理事件。这里的"依次”和“合适”的含义是:
  • 如果是inbound事件,会从头到尾按顺序调用双向链表上的ChannelInboundHandler类型的handler。
  • 如果是outbound事件,会从尾到头按顺序调用双向链表上的ChannelOutboundHandler类型的handler。
  piplePile确保一个handler调用始终在一个唯一的eventExecutor中,这个eventExecutor可能是channel的eventLoop,也可能是从用户指定的eventExecutorGroup中分配到的一个executor。

netty源码解解析(4.0)-8 ChannelPipeline的设计的更多相关文章

  1. netty源码解解析(4.0)-10 ChannelPipleline的默认实现--事件传递及处理

    事件触发.传递.处理是DefaultChannelPipleline实现的另一个核心能力.在前面在章节中粗略地讲过了事件的处理流程,本章将会详细地分析其中的所有关键细节.这些关键点包括: 事件触发接口 ...

  2. netty源码解解析(4.0)-11 Channel NIO实现-概览

      结构设计 Channel的NIO实现位于io.netty.channel.nio包和io.netty.channel.socket.nio包中,其中io.netty.channel.nio是抽象实 ...

  3. netty源码解解析(4.0)-17 ChannelHandler: IdleStateHandler实现

    io.netty.handler.timeout.IdleStateHandler功能是监测Channel上read, write或者这两者的空闲状态.当Channel超过了指定的空闲时间时,这个Ha ...

  4. netty源码解解析(4.0)-18 ChannelHandler: codec--编解码框架

    编解码框架和一些常用的实现位于io.netty.handler.codec包中. 编解码框架包含两部分:Byte流和特定类型数据之间的编解码,也叫序列化和反序列化.不类型数据之间的转换. 下图是编解码 ...

  5. netty源码解解析(4.0)-20 ChannelHandler: 自己实现一个自定义协议的服务器和客户端

    本章不会直接分析Netty源码,而是通过使用Netty的能力实现一个自定义协议的服务器和客户端.通过这样的实践,可以更深刻地理解Netty的相关代码,同时可以了解,在设计实现自定义协议的过程中需要解决 ...

  6. netty源码解解析(4.0)-15 Channel NIO实现:写数据

    写数据是NIO Channel实现的另一个比较复杂的功能.每一个channel都有一个outboundBuffer,这是一个输出缓冲区.当调用channel的write方法写数据时,这个数据被一系列C ...

  7. netty源码解解析(4.0)-14 Channel NIO实现:读取数据

     本章分析Nio Channel的数据读取功能的实现. Channel读取数据需要Channel和ChannelHandler配合使用,netty设计数据读取功能包括三个要素:Channel, Eve ...

  8. netty源码解解析(4.0)-4 线程模型-概览

    netty线程体系概览 netty的高并发能力很大程度上由它的线程模型决定的,netty定义了两种类型的线程: I/O线程: EventLoop, EventLoopGroup.一个EventLoop ...

  9. netty源码解解析(4.0)-12 Channel NIO实现:channel初始化

    创建一个channel实例,并把它register到eventLoopGroup中之后,这个channel然后处于inactive状态,仍然是不可用的.只有在bind或connect方法调用成功之后才 ...

随机推荐

  1. Python3实战系列之七(获取印度售后数据项目)

    问题:续接上一篇.说干咱就干呀,勤勤恳恳写程序呀! 目标:此篇开始进入正题了.为实现我们整个项目功能而开始实现各个子模块功能.首先实现第一篇列出的分步功能模块的第四步: 4.python读取excel ...

  2. log4net 写日志

    转载地址:https://www.cnblogs.com/vichin/p/6022612.html   //基本使用 https://www.cnblogs.com/genesis/p/498562 ...

  3. 别人的Linux私房菜(5)首次CentOS7与帮助等

    ctrl alt F1-F6切换终端tty1-6,其中,F1的终端带有用户界面. 在终端登录后,输入startx启动个人图形界面.(启动有一些条件限制,如没有其他的X Window启用,已经安装,并具 ...

  4. javascript 错误监控

    一.错误分类 1,即使运行错误:代码错误, 2.资源加载错误 二. 错误的捕获方式 1.即使运行错误的捕获方式 a. try catch       b.window.onerror 2.资源加载错误 ...

  5. ABP框架系列之三:(Entity Framework Integration-实体框架集成)

    ASP.NET Boilerplate can work with any O/RM framework. It has built-in integration with EntityFramewo ...

  6. 单台机器安装zookeeper

    先给一堆学习文档,方便以后查看 官网文档地址大全: OverView(概述) http://zookeeper.apache.org/doc/r3.4.6/zookeeperOver.html Get ...

  7. scala字符串前加s使用$

    https://my.oschina.net/u/2000675/blog/1592140 字符串中的变量替换,Scala中基础的字符串插值就是在字符串前加字幕‘s’,然后在字符串中放入变量,每个变量 ...

  8. Codeforces Round #512 (Div. 2) D. Vasya and Triangle

    参考了别人的思路:https://blog.csdn.net/qq_41608020/article/details/82827632 http://www.cnblogs.com/qywhy/p/9 ...

  9. Linux 查看IP

    UBuntu 系统下 按Ctrl+Alt+T 唤出终端 在终端输入: ifconfig 命令 点击回车 就可以看到自己电脑在局域网的IP地址了 图中第二行 inet 地址:192.168.1.101 ...

  10. 了解Java基本数据类型的取值范围

    拿byte类型做栗子 一个字节是8位二进制数,然后最高位会用来作为符号位.正数计算机是存的原码,负数是存的补码. 也就说byte正数最大是0111 1111,转化为十进制是:127(这就是byte的上 ...