Netty组件入门学习

Channel、EventLoop和ChannelFuture

  1. Channel——Socket;
  2. EventLoop——控制流、多线程处理、并发
  3. ChannelFuture异步通知

Channel接口

基于I/O操做(例如:bind()、connect()、read()和write())依赖于底层网络传输提供的原语。在基于Java的网络编程中,其基本构造为类Socket。

Netty的Channel接口所提供的API,大大下降了直接使用Socket类的复杂性。

Channel拥有许多预约义的、专门化实现的普遍类层次结构的根,以下:编程

  1. EmbeddedChannel
  2. LocalServerChannel
  3. NioDatagramChannel
  4. NioSctpChannel
  5. NioSocketChannel

EventLoop接口

EventLoop定义了Netty的核心抽象,用于处理链接的生命周期中所发生的事件。服务器

Channel、EventLoop、Thread、EventLoopGroup关系示意图网络

关系图

  • 一个EventLoopGroup包含一个或者多个EventLoop
  • 一个EventLoop在它的生命周期内只和一个Thread绑定
  • 全部由EventLoop处理的I/O事件都将在它专有的Thread上被处理
  • 一个Channel在它的生命周期内只注册于一个EventLoop
  • 一个EventLoop可能会被分配一个或多个Channel

一个给定Channel的I/O操做都是由相同的Thread执行的,实际上消除了对于同步的须要多线程

ChanneFuture接口

Netty中全部的I/O操做都是异步的,由于一个操做不可能当即返回,因此咱们须要一种用于在以后的某个时间点肯定其结果的方法。

所以Netty提供了ChannelFuture接口,其addListener()方法注册了一个ChannelFutureListener,以便在某个操做完成时(不管是否成功)获得通知。并发

ChannelHandler和ChannelPipeline

主要用来管理数据流已经执行应用程序处理逻辑异步

ChannelHandler接口

ChannelHandler充当了全部处理入站和出站数据的应用程序逻辑的容器。

ChannelHandler可专门用于几乎任何类型的动做,例如将数据从一种格式转换为另一种格式,或者处理转换过程当中所抛出的异常。

ChannelHandler能够用来接收入站事件和数据,随后使用应用程序的业务逻辑进行处理。当你的客户端须要发送响应时,能够从ChannelInboundhandler冲刷数据。

你的应用程序的业务逻辑一般驻留在一个或者多个ChannelInboundHandler中。oop

ChannelPipeline

ChannelPipeline是ChannelHandler链的容器,并定义用于在该链上传播入站和出站事件流的API。当Channel被建立时,它会被自动地分配到它专属的ChannelPipeline。
编码

ChannelHandler被安装到ChannelPipeline中过程以下:spa

  1. 一个ChannelInitializer的实现被注册到了ServerBootstrap中
  2. 当ChannelInitializer.initChannel()方法被调用时,ChannelInitalizer将在ChannelPipeline中安装一组自定义的ChannelHandler
  3. ChannelInitializer将它本身从ChannelPipeline中移除

 ChannelHandler可让事件流经ChannelPipeline,它们是在应用程序的初始化或者引导阶段被安装的。这些对象接收事件、执行它们所实现的处理逻辑,并将数据传递给链中的下一个ChannelHandler。它们的执行顺序是由它们被添加的顺序决定的

ChannelPipeline是这些ChannelHandler的编排顺序。线程

入站和出站ChannelHandler能够被安装到同一个ChannelPipeline中。若是一个消息或者任何其余的入站事件被读取,那么它会从ChannelPipeline的头部开始流动,并被传递给第一个ChannelInboundHandler。这个ChannelHandler不必定会实际地修改数据,具体取决于它的具体功能,在这以后,数据将会被传递给链中的下一个ChannelInboundHandler。最终,数据会到达ChannelPipeline的尾端,届时,全部处理就都结束了。

出站数据将会从ChannelOutboundHandler链的尾端开始流动,直到它到达链的头部为止。在这以后,出站数据将会到达网络传输层。

经过使用做为参数传递到每一个方法的ChannelHandlerContext,事件能够被传递给当前ChannelPipeLine中的下一个ChannelHandler。由于用户并非关心全部的事件,所以Netty提供了抽象类ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter。经过调用ChannelHandlerContext上的对应的方法,均可以简单地将事件传递给下一个ChannelHandler的方法的实现。

当ChannelHandler被添加到ChannelPipeline时,它将会被分配一个ChannelHandlerContext,它表明了Channel和ChannelPipeline之间的绑定。虽然这个对象能够被用于获取底层的Channel,可是它主要仍是被用于出站写数据。

在Netty中,有两种发送消息的方式:

  1. 直接写到Channel中,会致使消息从ChannelPipeline的尾端开始流动
  2. 写到和ChannelHandler相关联的ChannelHandlerContext对象中,会致使消息从ChannelPipeline中的下一个ChannelHandler开始流动

若是将两个类别(Inboud和Outbound)的ChannelHandler都混合添加到一个ChannelPipeline会发生什么?

虽然ChannelInboundHandler和ChannelOutboundHandler都扩展自ChannelHandler,可是Netty能够区分两种Handler的实现,并确保数据只会在具备相同定向类型的两个ChannelHandler之间传递。

深刻了解ChannelHandler

不一样类型的ChannelHandler各自的功能主要取决于它们的超类。Netty以适配器类的形式提供了大量默认的ChannelHandler实现,其旨在简化应用程序处理逻辑的开发过程。

这些适配器类能够自动将事件转发到ChannelPipeline中的下一个ChannelHandler,因此你能够只重写那些你想要特殊处理的方法和事件。

为何须要适配器?

有一些适配器类能够将编写自定义的ChannelHanlder所须要的努力降到最低限度,由于它们提供了定义在对应接口中的全部方法的默认实现。
经常使用的适配器类有:

  • ChannelHandlerAdapter
  • ChannelInboundHandlerAdapter
  • ChannelOutboundHandlerAdapter
  • ChannelDuplexHandler

编码解码器

全部由Netty提供的编码/解码适配器类都实现了ChannelOutboundHandler或者ChannelInboundHandler接口。

对于入站数据,channelRead方法已经被重写了。对于每个从入站Channel读取的消息,这个方法都会被调用。随后,它将调用由预置解码器提供的decode()方法,并将已解码的字节转发给ChannelPipeline中的下一个ChannelHandler,出站相反。

抽象类SimpleChannelInboundHandler

最多见的一个状况,你的应用程序会利用一个ChannelHandler来接受解码消息,并对该数据应用业务逻辑。要建立一个这样的ChannelHandler,只须要扩展SimpleChannelInboundHandler<T>,其中<T>是你要处理的消息的Java类型。

在这个ChannelHandler中,你将须要重写基类的一个或者多个方法,而且获取一个ChannelHandlerContext的引用,这个引用将做为参数传递给ChannelHandler的全部方法。

在这种类型的ChannelHandler中,最重要的方法是channelRead0(ChannelHandlerContext , T)。除了要求不阻塞当前的I/O线程以外,其具体实现彻底取决于你。

引导

Netty的引导类为应用程序的网络层配置提供了容器。

  1. 用于客户端(Bootstrap)引导,将一个进程链接到另外一个运行在某个指定主机的指定端口上的进程。
  2. 用于服务器(ServerBootstrap)引导,将一个进程绑定到某个指定的端口

Bootstrap类比较

类别 Bootstrap ServerBootstrap
网络编程中的做用 链接到远程主机和端口 绑定到一个本地端口
EventLoopGroup的数目 1 2

区别分析:

  1. ServerBootstrap将绑定到一个端口,由于服务器必需要监听链接,而Bootstrap则是由想要链接到远程节点的客户端应用程序所使用的。
  2. 为何服务端须要两个EventLoopGroup(能够是同一个实例)?由于服务器须要两组不一样的Channel。第一组将只包含一个ServerChannel,表明服务器自身的已绑定到某个本地端口第二次正在监听的套接字。第二组包含全部已经建立的用来处理传入客户端链接(对于每一个服务器已经接受的链接都一个)的Channel。

3.与ServerChannel相关联的EventLoopGroup将分配一个负责为传入链接请求建立Channel的EventLoop。一旦链接被接受,第二个EventLoopGroup就会给它的Channel分配一个EventLoop。

具备两个EventLoopGroup的服务器

EventLoopGroup服务器

相关文章
相关标签/搜索