Netty组件
一、Channel、EventLoop 和ChannelFuture
这些类合在一起,可以被认为是Netty 网络抽象的代表:
- Channel—Socket;
- EventLoop—控制流、多线程处理、并发;
- ChannelFuture—异步通知。
Channel 接口
基本的I/O 操作(bind()、connect()、read()和write())依赖于底层网络传输所提供的原语。在基于Java 的网络编程中,其基本的构造是class Socket。Netty 的Channel 接
口所提供的API,大大地降低了直接使用Socket 类的复杂性。此外,Channel 也是拥有许多预定义的、专门化实现的广泛类层次结构的根,下面是一个简短的部分清单:
- EmbeddedChannel;
- LocalServerChannel;
- NioDatagramChannel;
- NioSctpChannel;
- NioSocketChannel。
EventLoop 接口
EventLoop 定义了Netty 的核心抽象,用于处理连接的生命周期中所发生的事件。我们将在第7 章中结合Netty 的线程处理模型的上下文对EventLoop 进行详细的讨论。目前,图3-1
在高层次上说明了Channel、EventLoop、Thread 以及EventLoopGroup 之间的关系。

这些关系是:
- 一个EventLoopGroup 包含一个或者多个EventLoop;
- 一个EventLoop 在它的生命周期内只和一个Thread 绑定;
- 所有由EventLoop 处理的I/O 事件都将在它专有的Thread 上被处理;
- 一个Channel 在它的生命周期内只注册于一个EventLoop;
- 一个EventLoop 可能会被分配给一个或多个Channel。
注意,在这种设计中,一个给定Channel 的I/O 操作都是由相同的Thread 执行的,实际上消除了对于同步的需要。
ChannelFuture 接口
正如我们已经解释过的那样,Netty 中所有的I/O 操作都是异步的。因为一个操作可能不会立即返回,所以我们需要一种用于在之后的某个时间点确定其结果的方法。为此,Netty 提供了ChannelFuture 接口,其addListener()方法注册了一个ChannelFutureListener,以便在某个操作完成时(无论是否成功)得到通知。
关于ChannelFuture 的更多讨论 可以将ChannelFuture 看作是将来要执行的操作的结果的占位符。它究竟什么时候被执行则可能取决于若干的因素,因此不可能准确地预测,但是可以肯定的是它将会被执行。此外,所有属于同一个Channel 的操作都被保证其将以它们被调用的顺序被执行。
我们将在第7 章中深入地讨论EventLoop 和EventLoopGroup。
二、ChannelHandler 和ChannelPipeline
2.1、ChannelHandler 接口
从应用程序开发人员的角度来看,Netty 的主要组件是ChannelHandler,它充当了所有处理入站和出站数据的应用程序逻辑的容器。这是可行的,因为ChannelHandler 的方法是
由网络事件(其中术语“事件”的使用非常广泛)触发的。事实上,ChannelHandler 可专门用于几乎任何类型的动作,例如将数据从一种格式转换为另外一种格式,或者处理转换过程
中所抛出的异常。
举例来说,ChannelInboundHandler 是一个你将会经常实现的子接口。这种类型的ChannelHandler 接收入站事件和数据,这些数据随后将会被你的应用程序的业务逻辑所处
理。当你要给连接的客户端发送响应时,也可以从ChannelInboundHandler 冲刷数据。你的应用程序的业务逻辑通常驻留在一个或者多个ChannelInboundHandler 中。
2.2、ChannelPipeline 接口
ChannelPipeline 提供了ChannelHandler 链的容器,并定义了用于在该链上传播入站和出站事件流的API。当Channel 被创建时,它会被自动地分配到它专属的ChannelPipeline。
ChannelHandler 安装到ChannelPipeline 中的过程如下所示:
- 一个ChannelInitializer的实现被注册到了ServerBootstrap中①;
- 当ChannelInitializer.initChannel()方法被调用时,ChannelInitializer将在ChannelPipeline 中安装一组自定义的ChannelHandler;
- ChannelInitializer 将它自己从ChannelPipeline 中移除。
为了审查发送或者接收数据时将会发生什么,让我们来更加深入地研究ChannelPipeline和ChannelHandler 之间的共生关系吧。
ChannelHandler 是专为支持广泛的用途而设计的,可以将它看作是处理往来ChannelPipeline 事件(包括数据)的任何代码的通用容器。图3-2 说明了这一点,其展示了从Channel-
Handler 派生的ChannelInboundHandler 和ChannelOutboundHandler 接口。

使得事件流经ChannelPipeline 是ChannelHandler 的工作,它们是在应用程序的初始化或者引导阶段被安装的。这些对象接收事件、执行它们所实现的处理逻辑,并将数据传递给
链中的下一个ChannelHandler。它们的执行顺序是由它们被添加的顺序所决定的。实际上,被我们称为ChannelPipeline 的是这些ChannelHandler 的编排顺序。
图3-3 说明了一个Netty 应用程序中入站和出站数据流之间的区别。从一个客户端应用程序的角度来看,如果事件的运动方向是从客户端到服务器端,那么我们称这些事件为出站的,反之则称为入站的。

2.3、更加深入地了解ChannelHandler
正如我们之前所说的,有许多不同类型的ChannelHandler,它们各自的功能主要取决于它们的超类。Netty 以适配器类的形式提供了大量默认的ChannelHandler 实现,其旨在简化
应用程序处理逻辑的开发过程。你已经看到了,ChannelPipeline中的每个ChannelHandler将负责把事件转发到链中的下一个ChannelHandler。这些适配器类(及它们的子类)将自动执行这个操作,所以你可以只重写那些你想要特殊处理的方法和事件。
为什么需要适配器类
有一些适配器类可以将编写自定义的ChannelHandler 所需要的努力降到最低限度,因为它们提
供了定义在对应接口中的所有方法的默认实现。
下面这些是编写自定义ChannelHandler 时经常会用到的适配器类:
ChannelHandlerAdapter
ChannelInboundHandlerAdapter
ChannelOutboundHandlerAdapter
ChannelDuplexHandler
2.4、3 个ChannelHandler 的子类型:编码器、解码器和SimpleChannelnboundHandler<T> —— ChannelInboundHandlerAdapter 的一个子类。
编码器和解码器
入站消息会被解码;也就是说,从字节转换为另一种格式,通常是一个Java 对象。
出站消息,则会发生相反方向的转换:它将从它的当前格式被编码为字节。
这两种方向的转换的原因很简单:网络数据总是一系列的字节。
Netty中的解码和编码的基类的名称将类似于ByteToMessageDecoder 或MessageToByteEncoder。对于特殊的类型,你可能会发现类似于ProtobufEncoder 和ProtobufDecoder
这样的名称——预置的用来支持Google 的Protocol Buffers。除此之外,Netty还提供了一些编码器/解码器适配器类,这些适配器类都实现了ChannelOutboundHandler 或者ChannelInboundHandler 接口。
三、引导类
Netty 的引导类为应用程序的网络层配置提供了容器,这涉及将一个进程绑定到某个指定的端口,或者将一个进程连接到另一个运行在某个指定主机的指定端口上的进程。
通常来说,我们把前面的用例称作引导一个服务器,后面的用例称作引导一个客户端。虽然这个术语简单方便,但是它略微掩盖了一个重要的事实,即“服务器”和“客户端”实际上表示了不同的网络行为;换句话说,是监听传入的连接还是建立到一个或者多个进程的连接。
有两种类型的引导:一种用于客户端(简单地称为Bootstrap),而另一种(ServerBootstrap)用于服务器。
比较Bootstrap 类
| 类 别 | Bootstrap | ServerBootstrap |
| 网络编程中的作用 | 连接到远程主机和端口 | 绑定到一个本地端口 |
| EventLoopGroup | 1 | 2① |
注释:ServerBootstrap 类也可以只使用一个EventLoopGroup,此时其将在两个场景下共用同一个EventLoopGroup。
这两种类型的引导类之间的第一个区别已经讨论过了:ServerBootstrap 将绑定到一个端口,因为服务器必须要监听连接,而Bootstrap 则是由想要连接到远程节点的客户端应用程
序所使用的。
第二个区别可能更加明显。引导一个客户端只需要一个EventLoopGroup,但是一个ServerBootstrap 则需要两个(也可以是同一个实例)。为什么呢?
因为服务器需要两组不同的Channel。第一组将只包含一个ServerChannel,代表服务器自身的已绑定到某个本地端口的正在监听的套接字。而第二组将包含所有已创建的用来处理传入客户端连接(对于每个服务器已经接受的连接都有一个)的Channel。图3-4 说明了这个模型,并且展示了为何需要两个不同的EventLoopGroup。

与ServerChannel 相关联的EventLoopGroup 将分配一个负责为传入连接请求创建Channel 的EventLoop。一旦连接被接受,第二个EventLoopGroup 就会给它的Channel
分配一个EventLoop。
Netty组件的更多相关文章
- 从netty-example分析Netty组件续
上文我们从netty-example的Discard服务器端示例分析了netty的组件,今天我们从另一个简单的示例Echo客户端分析一下上个示例中没有出现的netty组件. 1. 服务端的连接处理,读 ...
- Netty 源码(一)Netty 组件简介
Netty 源码(一)Netty 组件简介 Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) 一.Netty 架构 Core: ...
- 从netty-example分析Netty组件
分析netty从源码开始 准备工作: 1.下载源代码:https://github.com/netty/netty.git 我下载的版本为4.1 2. eclipse导入maven工程. netty提 ...
- Netty组件介绍(转)
http://www.tuicool.com/articles/mEJvYb 为了更好的理解和进一步深入Netty,我们先总体认识一下Netty用到的组件及它们在整个Netty架构中是怎么协调工作的. ...
- Netty组件理解(转载)
转载的文章,写的非常好. 一.先纵览一下Netty,看看Netty都有哪些组件? 为了更好的理解和进一步深入Netty,我们先总体认识一下Netty用到的组件及它们在整个Netty架 ...
- Netty学习笔记(二)——netty组件及其用法
1.Netty是 一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. 原生NIO存在的问题 1) NIO的类库和API繁杂,使用麻烦:需要熟练掌握Selector.Se ...
- Netty 框架学习 —— Netty 组件与设计
Channel.EventLoop 和 ChannelFuture 这一节将对 Channel.EventLoop 和 ChannelFuture 类进行讨论,它们组合在一起,可以被认为是 Netty ...
- Netty 组件分析
EventLoop 事件循环对象 EventLoop 本质是一个单线程执行器(同时维护了一个 Selector),里面有 run 方法处理 Channel 上源源不断的 io 事件. 它的继承关系比较 ...
- Netty是什么?
Netty是什么? 本质:JBoss做的一个Jar包 目的:快速开发高性能.高可靠性的网络服务器和客户端程序 优点:提供异步的.事件驱动的网络应用程序框架和工具 通俗的说:一个好使的处理Socket的 ...
随机推荐
- JSP 分页代码
jsp 分页模板 后台分页代码: 说明: 在 com.zc.domain 包下: PageBean.java 文件 package cn.itcast.customer.domain; impor ...
- 【模式识别】CART和GML AdaBoost MATLAB TOOLBOX
GML AdaBoost Matlab Toolbox是一款很优秀的AdaBoost工具箱,内部实现了Real AdaBoost, Gentle AdaBoost和Modest AdaBoost三种方 ...
- Docker学习总结之docker创建私有仓库(private Repositories)
Docker 创建 Private Repositories 前言 基于GFW的缘故,国内大陆基本无法pull国外的镜像,更别说官方的index了.如果images无法pull下来,那么docker就 ...
- Struts2之ModelDriven的使用
http://www.cnblogs.com/luoyanli/archive/2012/11/20/2778361.html 我们可以根据Action属性的不同将它分为两类:Field-Driven ...
- mssql-在一个特定的会话停止出发器
用SET CONTEXT_INFO来实现 --在某个会话里设置 SET CONTEXT_INFO 0x8888 --在触发器里判断 ) SELECT @Cinfo = Context_Info() 原 ...
- Python基础(2)_数字和字符串类型
一.数据类型 1.数字 整型 Python的整型相当于C中的long型,Python中的整数可以用十进制,八进制,十六进制表示. >>> --------->默认十进制 > ...
- UVALive - 7045 Last Defence 【数学】
题目链接 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...
- js完美实现table分页
// JavaScript Document /** * js分页类 * @param iAbsolute 每页显示记录数 * @param sTableId 分页表格属性ID值,为String * ...
- Java实现将一段汉字变成unicode码
public class T { public static void main(String[] args) { String s = "java 中文编码"; System.o ...
- zabbix实现mysql数据库的监控(一)
zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案.它能监视各种网络参数,保证服务器系统的安全运营:并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问 ...