Channel,EventLoop和ChannelFuture

这三者可以看作是Netty网络架构的抽象

  • Chennel-Sockets
  • EvnetLoop-流控(Control flow),多线程,并发
  • ChannelFuture - 异步通知

Channel接口

基本的IO操作(bind(),connect(),read(),write())都是基于底层的网络传输。在Java网络编程中,基础构建是Socket类,但是直接基于Socket进行编程会很繁琐。Netty的Channel接口提供的API能大大地减小直接对Socket进行编程的复杂性。另外,Channel又是很多实现了特定需求的Channel的顶层抽象接口,这些Channel接口的实现类有:

  • EmbeddedChannel
  • LocalServerChannel
  • NioDatagramChannel
  • NioSctpChannel
  • NioSocketChannel

EventLoop接口

EventLoop用来处理一个连接(connection)生命周期内发生的事件。下图在高层次上描述了Channel、EventLoop、Thread和EventLoopGroup之间的关系。

这些关系有:

  • EventLoopGroup包含一个或多个EventLoop
  • 一个EvnetLoop实例绑定到了一个线程在它(EvnetLoop)的生命周期内。
  • 所有被EventLoop操作的IO事件都是在它专有的线程中处理
  • 一个Channel在它的生命周期中被注册到一个EventLoop中,然后这个EventLoop就会为这个Channel处理所有的IO操作
  • 一个EventLoop实例能注册多个Channel

注意在这种设计中,给定Channel的IO操作都是在同一个线程中执行,无形中就不需要进行同步。

ChannelFuture接口

Netty中的所有IO操作都是异步的。因为一个操作的结果可能不会马上返回,所以我们需要一种能够在未来获取它的结果的方式。为此,Netty提供了ChannelFuture,它的addListener()方法注册了一个ChannelFutureListener,通过这个ChannelFutureListener就能在操作完成(不管有没有成功)时得到通知。

ChannelHandler和ChannelPipeline

ChannelHandler接口

站在应用程序开发者的角度来看,Netty主要的组件就是ChannelHandler,它作为所有为传入和传出数据提供处理的应用业务逻辑的容器。通常实现它(或继承实现了它的类)来提供业务逻辑。这是可能的因为ChannelHandler的方法会被网络事件触发。实际上,ChannelHandler能被用于任意类型的操作,比如,数据的格式转换或处理操作过程中抛出的异常。

你通常需要实现的是ChannelHandler的子接口ChannelInboundHandler。这个子接口能接收你业务逻辑需要处理的数据或者事件。当你要发送一个回复给客户端的时候,你能从ChannelInboundHandler中flush数据。你的业务逻辑通过会依赖于多个ChannelInboundHandler

ChannelPipeline接口

ChannelPipeline为一连串的ChannelHandler提供容器同时定义了用于传播链中传入数据和传出数据事件流的API。Channel被创建后会自动的分配到它自己的ChannelPipeline

ChannelHandler通过如下的步骤被加载到ChannelPipeline中:

  • 一个ChannelInitializer的实现注册到ServerBootstrap
  • ChannelInitializer.initChannel()方法被调用,ChannelInitializer装载了一系列自定义的ChannelHandlers到pipeline中。
  • ChannelInitializer把它自己从ChannelPipeline中移除掉
    ChannelHandler具有广泛的用途,你能把它想成一个为任何处理在ChannelPiple中流通(传入传出)的事件(包括数据)的代码的通用容器(generic container)。下图说明了ChannelInboundHandlerChannelOutboundHandler继承自ChannelHandler的关系。


事件通过在初始化或启动应用期间加载的ChannelHandler在pipeline中传递,ChannelHandler接受事件并执行在其中实现了的业务逻辑,并将数据传递给(handler)链中的下一个handler。这些handler根据它们被添加的顺序来执行。

上图展示了Netty应用中输入(数据)流和输出(数据)流的区别。对于客户端来说,从客户端到服务器事件就是传出去(outbound)的反之就是传进来(inbound)的。

inbound和outbound handler都能安装到同一个pipeline。如果读到一条消息或者其他传入(inbound)事件,它会从这条pipeline的头部(head)开始然后传递给第一个ChannelInboundHandler。这个handler可能会也可能不会真的修改数据,这取决于它的具体函数,然后数据会传递给下一个handler。最终,数据回到达pipeline的末尾(tail),此时所有的处理都结束了。

数据传出(outbound)的移动(也就是数据被写)与传入同理。这种情况下,数据从尾部流到头部。

因为传出数据和传入数据是有区别的,你可能想知道当这两种不同的操作都混在了同一个ChannelPipeline时会发生什么。虽然inbound和outbound handler都继承了ChannelHandler,Netty提供了分别的实现(ChannelInboundHandler好ChannelOutbouondHandler)同时确保数据只会在同一个方向的handler中传递。

当一个ChannelHandler被添加到ChannelPipeline中,它会被分配一个代表ChannelHandlerChannelPipeline之间绑定关系的一个ChannelHandlerContext。尽管可以通过这个Context获取底层的Channel实例,但是它主要用来写传出数据(write outbound data)。

在Netty中有两种发送数据的方式。你既可以直接写到Channel里面又可以写到与ChannelHander相关的ChannelHandlerContext中。前者会使数据从ChannelPipeline的末尾开始传输,后者会使数据从ChannelPipeline中下一个handler开始。

更深入的了解ChannelHandler

正如我们前面说到的,Netty提供了不同类型的ChannelHandler,它们的功能很大程度上是由它们的超类决定。Netty以适配器(adapter)类的方式提供了许多默认的handler实现以简化应用业务逻辑的开发。你已经知道在一个pipeline中每一个ChannelHandler都负责把事件传递给下一个handler。这些适配器类(以及它们的子类)会自动这么做,因此你可以只重写你感兴趣的方法和事件。

接下来我们来了解3个ChannelHandler的子类:encoders,decoders以及SimpleChannelInboundHandler(一个ChannelInboundHandlerAdapter的子类)。

encoder和decoder

当你通过Netty收发消息时,一个数据的转换就会发生。传入的消息会被解码(decode),从字节转换成其他的格式,通常是一个Java对象。如果是传出的消息,那么就会把数据从当前的格式转换为字节。因为网络数据总是字节流的。

Netty为编码解码提供了大量与特定需求相关的抽象类。比如,你的应该可能会使用一个中间(intermediate)格式,不需要将消息马上转换为字节。你仍然需要一个编码器(encoder),但它可从不同的超类中继承。为了决定使用哪一个,你可以应用一个简单的命名约定(apply a simple naming convention)。

通常,基类会有像ByteToMessageDecoderMessageToByteEncoder的类名。在具体的实现类中,有与Protobuf相关的ProtobufEncoderProtobufDecoder

所有的编码解码适配器类都实现了ChannelInboundHandlerChannelOutboundHandler

对于传入数据来说,你会发现channelRead方法或事件被重写了。这个方法会被从传入数据(inbound)Channel读到的消息调用。然后会通过提供的decoder调用decode()方法然后将解码了的字节(解码成Java对象)传递给下一个ChannelInboundHandler

对于传出数据来说就是相反的,一个encoder将消息转换成字节然后传递给一下handler。

SimpleChannelInboundHandler抽象类

通常你的应用需要使用一个handler来接收一个解码了的数据然后应用一些业务逻辑。为了创建这样只有个handler,你只需要继承SimpleChannelInboundHandler<T>T就是你想要处理的数据的Java类型。

这个类中最重要的方法是channelRead0(ChannelHandlerContext ctx,T t)。它的实现完全取决于你,除非需要当前IO线程不被阻塞。

bootstrap

Nettyd的bootstrap类为配置一个应用网络层的容器,这涉及到给一个特定的端口号绑定一个程序(process)(通常是用于启动服务器);或连接一个程序到另一个在特定的主机和端口号运行的程序(通常是用于启动一个客户端)。也就是监听连接请求或建立连接。

严格的说术语连接指的是面向连接协议如TCP,它可以保证传输数据的有序性。

因此,有两种bootstrap:一种是为客户端设计的,就叫Bootstrap;另一种是为服务端设计的(ServerBootstrap)。

下表比较了这两种类的区别:

分类 Bootstrap ServerBootstrap
网络功能 连接到远程的主机和端口 绑定到一个本地端口
EventLoopGroup的数量 1 2

我们重点解释一下第二个不同,启动一个客户端只需要一个EventLoopGroup,但服务端需要两个(可以使同一个实例)。为啥子呢?

一个服务器需要两个不同的Channel集合。第一个集合包含一个ServerChannel代表服务器自己绑定了本地端口的监听socket。第二个集合会包含所有被创建来处理客户端连接的Channel。下图展示了这个模型。

ServerChannel相关的EventLoopGroup(左边的)分配EventLoop来处理为连接请求创建ServerChannel,一旦一个连接被接收,第二个EventLoopGroup就为这个Channel分配一个EventLoop

Netty in action—Netty组件和设计相关推荐

  1. Netty系列之Netty基础概念与组件

    什么是Netty,Netty各个组件介绍 本部分转载自 Java技术债务[什么是Netty?为什么使用Netty?Netty有哪些组件?] 原文链接:https://blog.csdn.net/qq_ ...

  2. Netty In Action中文版

    第一章:Netty介绍 本章介绍 Netty介绍 为什么要使用non-blocking IO(NIO) 阻塞IO(blocking IO)和非阻塞IO(non-blocking IO)对比 Java ...

  3. 《Netty IN ACTION》中文版《Netty实战》翻译手记——不负好时光

    不负好时光--<Netty in Action>中文版<Netty实战>翻译手记 引子 "书中自有黄金屋,书中自有颜如玉",这句话从小我老爸就给我讲,当然那 ...

  4. Netty in Action 读书

    Netty in Action 作者: Norman Maurer / Marvin Allen Wolfthal 出版社:Manning Publications 出版年:2015-12-31 页数 ...

  5. Netty In Action中文版 - 第十二章:SPDY

    Netty In Action中文版 - 第十二章:SPDY 本章我将不会直接翻译Netty In Action书中的原文,感觉原书中本章讲的很多废话,我翻译起来也吃力.所以,本章内容我会根据其他资料 ...

  6. 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 如何 ?

    [读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 如何 ? 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...

  7. 蚂蚁金服面对亿级并发场景的组件体系设计

    来自:蚂蚁金服公众号mPaas 作者:吕丹(凝睇),2011 年加入支付宝,先后负责了支付宝 Wap.alipass 卡券.SYNC 数据同步等项目,并参与了多次双十一.双十二.春节红包大促活动,在客 ...

  8. Netty学习1——Netty的核心组件

    Netty的核心组件 Netty的主要构件块:Channel.回调.Future.事件和ChannelHandler 1.Channel Channel是Java NIO的一个基本构造. 它代表一个到 ...

  9. Netty 快速开始(netty websocket客户端使用流程)

    文章目录 一.网络IO的基本知识与概念 1. 同步.异步.阻塞.非阻塞概念 2. IO模型 3. NIO和IO有什么区别? 4. Java NIO 工作流程 二.netty 1. 什么是netty? ...

  10. Netty系列之Netty线程模型

    关注点在于:如何灵活的动态绑定IO事件处理,又能进行串行化处理减少锁的使用 摘自:http://www.infoq.com/cn/articles/netty-threading-model 1. 背 ...

最新文章

  1. 简单介绍使用Nginx限制百度蜘蛛频繁抓取的问题
  2. linux 查看 定时任务 crontab 日志记录
  3. phrases practice_七年级短语、固定搭配练习题Phrases practice for Grade seven
  4. 纯CSS实现React Logo图形,内含详细解析
  5. vue垂直布局_vue实现长图垂直居上 vue实现短图垂直居中
  6. linux CentOS7最小化安装环境静默安装Oracle11GR2数据库(配置数据库监听_09)
  7. 蔚来测开提前批面试(一面)
  8. Oracle varchar类型数值排序问题
  9. Java发送form-data请求实现文件上传
  10. 1.Shell 编程从入门到精通 --- 第一个 Shell 程序
  11. android开发案例1---拦截电话,拯救史迪仔,有序广播
  12. Who Is Answering My Quries:Understanding and Characterizing Interception of the DNS Resolution Path
  13. 嵌入式硬件学习——分压电路
  14. 简述SD卡的工作原理(四)
  15. 论文阅读-Social Fingerprinting:detection of spambot groups through DNA-inspired behavioral modelingCCFA
  16. 数学建模之图论最短路径问题
  17. DDD中的“领域模型”
  18. C# 利用Excel及Spire.xls实现用户自定义打印模板
  19. XMU 1615 刘备闯三国之三顾茅庐(三) 【欧拉函数+快速幂+欧拉定理】
  20. ubuntu 取消打印队列命令

热门文章

  1. C++函数重载与引用的较好的练习实例
  2. springboot中解决servlet乱码问题,使用配置类注册过滤器解决
  3. 这些文章可以使知识融会贯通
  4. h5移动端flexible源码适配终端解读以及常用sass函数
  5. 顺序链表的C风格实现
  6. python webdriver 登录163邮箱发邮件加附件, 外加数据和程序分离,配置文件的方式...
  7. 【Android Studio安装部署系列】三十一、从Android studio3.0.0升级到Android studio3.0.1
  8. Linux kill 命令 以及USR1 信号解释
  9. Linux上mysql安装详细教程
  10. 分享小记:指数族分布