原文:https://blog.csdn.net/summerZBH123/article/details/79344226
--------------------- 

概述
    这篇文章主要是用来介绍netty中常用的一些组件,以及这些组件之间的存在关系

Channel  ----Socket
EventLoop ----控制流,多线程处理,并发;
ChannelHandler和ChannelPipeline
Bootstrap 和 ServerBootstrap
Channel 接口
     基本的I/O操作,在基于java 的网络编程中,其基本的构造是 Socket,在jdk中channel是通讯载体,在netty中channel被赋予了更多的功能。

用户可以有一下四类操作

查询channel状态
  配置channel参数
  进行channel支持的I/O操作(read,write,connect,bind)
  获取channel对应的ChannelPipeline, 从而自定义处理I/O事件和其他请求
Channel的生命周期
ChannelUnregistered  Channel已经被创建,但是还未注册到EventLoop;
 ChannelRegistered  Channel 已经被注册到EventLoop;
ChannelActive  Channel 处于活跃状态(已经连接到远程节点),可以进行接收和发送数据
ChannelInactive Channel 没有连接到远程节点
关于Channel状态查询的API

boolean isOpen(); // 是否开放 true 表示可用,false表示已经关闭,不可用
boolean isRegistered(); // 是否注册到一个EventLoop
boolean isActive(); // 是否激活 serverSocketChannel 表示已经绑定到端口,
// socketChannel表示channel可用,并且已经连接到对端
boolean isWritable(); // 是否可写
  正常的一个channel的状态流转

1、REGISTERED->CONNECT/BIND->ACTIVE->CLOSE->INACTIVE->UNREGISTERED
2、REGISTERED->ACTIVE->CLOSE->INACTIVE->UNREGISTERED
第一种是服务端用于绑定的channel,或者客户端发起绑定的channel,第二种是服务端接受的SocketChannel

注:

channel之间是有等级的,如果一个channel是由另外一个channel创建的,那么他们之间存在父子关系,比如,ServerSocketChannel 的accept() 方法返回的SocketChannel ,其父channel 就是ServerSocketChannel

如果一个channel不再使用的时候,需要调用其close()方法或者close(参数) 方法关闭,进行资源释放

Channel 中两个重要的api

EventLoop eventLoop();
ChannelPipeline pipeline();
    大多数情况下channel 都有一个与之关联的eventLoop ,如果没有说明还没有注册到eventLoop 上,NIO 中通过注册channel 通过注册到 selector 上而与一个 NioEventLoop 关联,当调用 eventLoop() 方法时,与之关联的 NioEventLoop 会被返回。

pipeline() 返回了当前 channel 所对应 ChannelPipeline() 对象,一个 channel 对应了一个 channelPipeline

这个可以看到 channel,channelPipeline, channelHandler 之间的关系

一个 channel 对应一个channelPipeline ,一个 channelPipeline 对应多个channelHandler

EventLoop 接口
    EventLoop 是用来处理连接的生命周期中所发生的事情,EventLoop, channel, Thread 以及 EventLoopGroup 之间的关系如下图:

这几个组件之间的关系总结下就是:

一个 EventLoopGroup 包含多个 EventLoop
一个 EventLoop 在他的生命周期中只和一个 Thread 绑定
所有的 EventLoop 处理的 I/O 事件都将在专有的 Thread 上处理
一个 Channel 在他的生命周期中只会注册一个 EventLoop
一个 EventLoop 会被分配给多个 Channel;
EventLoop 的线程管理
    如果当前调用的线程正是支撑 EventLoop 的线程,那么所提交的代码将会直接执行(这里可以调用 inEventLoop 或者是 inEventLoop(Thread thread ) 方法),否则,EventLoop 将调度该任务以便稍后执行,并将它放入到内部队列中去。当 EventLoop 下次处理他的事件时,它将会执行队列中的那些任务/事件。这也解释了任何的 Thread 是如何与 Channel 直接交互而无需在 ChannelHandler 中进行额外同步的。

注:每个 EventLoop 都有它自己的任务队列,独立于任何其他的 EventLoop 。

异步传输的实现:异步传输使用了少量的 EventLoop ,而且在当前的线程模型中,它可能被多个 channel 所共享。这样就尽可能少的 Thread 来支撑大量的 Channel

EventLoopGroup 为每个新创建的 Channel 分配一个 EventLoop。相同的 EventLoop 可能会被分配给多个 Channel 。一旦一个 Channel 分配给一个 EventLoop, 它将在你整个生命周期中都使用这个 EventLoop (以及其关联的 Thread )。这样就可以解释为什么 ChannelHandler 是线程安全的

注:对于BIO 这样的传输方式可能和 NIO 有所不同,每个 Channel 都将分配给一个 EventLoop (以及对应的 Thread )。其模型是:一个 EventLoopGroup 对应多一个 EventLoop ,一个 EventLoop 对应一个 Channel 。

注意, 因为 EventLoop 既需要执行 IO 操作, 又需要执行 task, 因此我们在调用 EventLoop.execute 方法提交任务时, 不要提交耗时任务, 更不能提交一些会造成阻塞的任务, 不然会导致我们的 IO 线程得不到调度, 影响整个程序的并发量.

ChannelHandler 接口
    ChannelHandler 充当了所有处理入站和出站数据的应用程序逻辑的容器。

ChannelHandler 的生命周期主要指的是 handler 添加到 ChannelPipeline 中,handler 从pipeline 中移除

ChannelHandler 主要是用来用来用户入站出站的工具,netty 中提供了一些开箱即用的处理器,本文只是介绍常见组件,以及他们之间的关系。

ChannelPipeline 接口
    ChannelPipeline 为 ChannelHandler 链提供了容器,当 channel 创建时,就会被自动分配到它专属的 ChannelPipeline ,这个关联是永久性的。

ChannelHandler 添加到 ChannlePipeline 的过程

一个 ChannelInitializer 的实现被注册到 ServerBootstrop 当中
当 ChannelInitializer.initChannel() 方法被调用时,ChannelInitializer 将在 ChannelPipeline 中安装一组自定义的 ChannelHandler
ChannelInitializer 将他自己从 ChannelPipeline 中移除;
    当 ChannelHandler 被添加到 ChannelPipeline 时,会被分配一个 ChannelHandlerContext ,代表的是 ChannelHandler 和 ChannelPipeline 之间的绑定。

注:Netty 中发送消息有两种方式,可以直接写入到 Channel 中,也可以写入到和 ChannelHandler 绑定的 ChannelHandlerContext 中。前者会使消息从 ChannelPipeline 当中尾部开始移动,后者会导致消息从 ChannelPipeline 中的下一个 ChannelHandler 中移动。

ChannelHandlerContext 接口
    ChannelHandlerContext 主要是用来管理它所关联的 ChannelHandler 和在同一个 ChannlePipeline 中其他的 ChannelHandler 之间的交互。

Bootstrap 和 ServerBootstrap(引导类)
       Bootstrap 和 ServerBootstrap 这两个引导类分别是用来处理客户端和服务端的信息,服务器端的引导一个父 Channel 用来接收客户端的连接,一个子 Channel 用来处理客户端和服务器端之间的通信,客户端则只需要一个单独的、没有父 Channel 的 Channel 来去处理所有的网络交互(或者是无连接的传输协议,如 UDP)

Bootstrap
       这个类主要是为客户端和无连接协议的应用程序创建 Channel, 创建步骤如下:

Bootstrap 在 bind() 方法被调用之后创建一个新的 Channel
Bootstrap 的 connect() 方法被调用后,也会创建一个新的 Channel
ServerBootstrap
      对于引导服务器

bind() 方法调用时,将会创建一个 ServerChannel
当连接被接受时,ServerChannel 将会创建一个新的子 Channel
ServerChannel 和子 Channel 之间是一对多的关系
    从 Channel 引导客户端

如:A 服务器正在处理客户端请求,同时需要 A 服务器作为客户端去访问 B 服务器,我们可以使用创建一个新的 eventLoop 来处理 A 和 B 之间的连接数据,我们之前说过每个 eventLoop 在其生命周期对应一个 Thread,显然一个连接创建一个 evetLoop 并不是最佳实践。推荐的办法是,使用 A 服务器中已经接受的子 Channel 的 EventLoop 直接拿过来使用,这样降低了线程的开销,同时降低了上下文之间的切换。

这段代码中,通过 ChannelHandlerContext 获取到当前连接的 Channel ,从而获取到与其关联的 EventLoop 对象。

这里可以大概先总结一下,之间的关系:

一个EventLoopGroup当中包含多个EventLoop
一个EventLoop在它的整个生命周期中只于一个thread进行绑定
所有由EventLoop所处理的各种I/O操作都将在它关联的Thread上进行处理
一个Channel在它的生命周期中只会注册在一个EventLoop上
一个EvenLoop在运行当中,会被分配给多个Channel
总结:netty当中,Channel的实现一定是是线程安全的,基于此,我们可以存储一个Channel的引用,并且在需要向远程发送数据时,通过这个引用来调用Channel相关的方法,即便当时有很多个线程都在使用,也不会出现多线程问题,而且消息是按照顺序发送出去的。

Netty中的基本组件及关系的更多相关文章

  1. Vue2.x中的父子组件相互通信

    业务场景:(这里指的是直接父子级关系的通信) 美女(子组件)将消息发送给大群(父组件) 大群(父组件)收到美女发送的消息后再回个信息给美女(子组件) 父组件 template <template ...

  2. 在Visual Studio中使用组件图描述项目组件依赖关系

    如果想描述项目组件的关系,可以考虑使用UML组建图. 在建模项目下添加一个名称为"Applicaiton Component Structure"的UML组建图. 添加各个组件,并 ...

  3. netty中的ByteBuf

    网络数据的基本单位总是字节.Java NIO 提供了 ByteBuffer 作为它 的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐. Netty 的 ByteBuffer 替代品是 ByteB ...

  4. netty中的Channel、ChannelPipeline

    一.Channel与ChannelPipeline关系 每一个新创建的 Channel 都将会被分配一个新的 ChannelPipeline.这项关联是永久性 的:Channel 既不能附加另外一个 ...

  5. Netty中的责任链模式

    适用场景: 对于一个请求来说,如果有个对象都有机会处理它,而且不明确到底是哪个对象会处理请求时,我们可以考虑使用责任链模式实现它,让请求从链的头部往后移动,直到链上的一个节点成功处理了它为止 优点: ...

  6. Netty 中的 handler 和 ChannelPipeline 分析

    上一节我们讲了 Netty 的启动流程,从启动流程入手分析了 Reactor 模型的第一步:channel 如何绑定 Selector.然后讲到了 EventLoop 在启动的时候发挥了什么作用.整个 ...

  7. 泛型编程、STL的概念、STL模板思想及其六大组件的关系,以及泛型编程(GP)、STL、面向对象编程(OOP)、C++之间的关系

    2013-08-11 10:46:39 介绍STL模板的书,有两本比较经典: 一本是<Generic Programming and the STL>,中文翻译为<泛型编程与STL& ...

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

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

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

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

随机推荐

  1. jmeter遇到问题及解决办法

    1.要得到前一个sampler的响应信息,是加beanshell sampler 还是加beanshell postprocessor?   答:在http取样器后添加beanshell sample ...

  2. SpringCloud----熔断机制 -- 断路器hystrix

    参考借鉴:http://www.cnblogs.com/chry/p/7279856.html SpringCloud Netflix实现了断路器库的名字叫Hystrix. 在微服务架构下,通常会有多 ...

  3. python学习-python入门

    开始学习python,开始记录. 第一个小程序:登陆系统 功能:1.通过文件名和密码导入用户名和密码~ 2.用户输入用户名和密码 3.将用户输入的用户名进行比对,先判断用户名是否在黑名单里面,如果在黑 ...

  4. ASP.NET Web API之消息拦截

    要在action执行前后做额外处理,那么ActionFilterAttribute和ApiControllerActionInvoker就派上用场了.比如客户端请求发过来的参数为用户令牌字符串toke ...

  5. TiDB初步概念

    阅读官方文档画以下路线图: 储存: rockDB用于单机数据固化:完全理解 raft用于分布式数据同步:完全理解 最终对外展示一整个完全有序的Key-Value序列:完全理解 重点:有序,就可以随机访 ...

  6. 《Pro SQL Server Internals, 2nd edition》

    设计和优化索引 定义一种应用于所有地方的索引策略是不可能的.每个系统都是独特的,需要基于工作,业务需求和其他一些因素的自己的索引方法.然而,有几个设计的注意事项和指导方针可以被应用到每个系统. 在我们 ...

  7. Android测试中常用的adb命令

    进入root权限adb root adb remount 重启手机 adb reboot 查看手机devices版本(adb是否连接手机) adb devices 点亮手机电源键/菜单键/home键 ...

  8. UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 199: illegal multibyte sequence

    =================================版权声明================================= 版权声明:原创文章 谢绝转载  请通过右侧公告中的“联系邮 ...

  9. redis命令List类型(六)

    Arraylist和linkedlist的区别?? Arraylist是使用数组来存储数据,特点:查询快.增删慢 Linkedlist是使用双向链表存储数据,特点:增删快.查询慢,但是查询链表两端的数 ...

  10. header头 下载文件 参数详解

    header( header( header( header( header( header( header( header( header( //2 浏览器不会响应缓存 //1 Public指示响应 ...