Netty 框架学习 —— Netty 组件与设计


Channel、EventLoop 和 ChannelFuture

这一节将对 Channel、EventLoop 和 ChannelFuture 类进行讨论,它们组合在一块儿,能够被认为是 Netty 网络抽象的表明:编程

  • Channel —— Socket
  • EventLoop —— 控制流、多线程处理、并发
  • CHannelFuture —— 异步通知

1. Channel 接口

Netty 的 Channel 接口对应 Java 网络编程的 Socket,大大下降了直接使用 Socket 类的复杂性。此外,Channel 也拥有其余预约义的实现类:服务器

  • EmbeddedChannel:测试 ChannelHandler
  • LocalServerChannel:用于同一个 JVM 内部实现 client 和 server 之间的通讯
  • NioSocketChannel:异步的客户端 TCP Socket 链接
  • NioServerSocketChannel:异步的服务器端 TCP Socket 链接
  • NioDatagramChannel:异步的 UDP 链接
  • NioSctpChannel:异步的客户端 Sctp 链接
  • NioSctpServerChannel:异步的 Sctp 服务器端链接
  • OioSocketChannel:同步的客户端 TCP Socket 链接
  • OioServerSocketChannel:同步的服务器端 TCP Socket 链接
  • OioDatagramChannel:同步的 UDP 链接
  • OioSctpChannel:同步的 Sctp 服务器端链接
  • OioSctpServerChannel:同步的客户端 TCP Socket 链接

2. EventLoop 接口

EventLoop 用于处理链接的生命周期中所发生的事件,下图说明了 Channel、EventLoop、Thread 以及 EventLoopGroup 之间的关系网络

这些关系是:多线程

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

3. ChannelFuture 接口

Netty 全部的 IO 操做都是异步的,一个操做可能不会当即返回结果,所以咱们须要一种用于在以后的某个时间点肯定其结果的方法。Netty 提供了 ChannelFuture 接口,其 addListener() 方法注册一个 ChannelFutureListener,以便在某个操做完成时(不管是否成功0获得通知)并发


ChannelHandler 和 ChannelPipeline

1. ChannelHandler 接口

ChannelHandler 能够看做是负责处理入站和出站数据的应用程序逻辑的容器,例如将数据从一个格式转换为另外一种格式,处理抛出的异常等等。ChannelInboundHandler 是一个常用的子接口,这种类型的 ChannelHandler 接收入站事件和数据,这些数据随后将被你的业务逻辑锁处理。当你想要给客户端发送响应时,也能够从 ChannelInboundHandler 冲刷数据,一般应用程序的业务逻辑一般驻留在一个或者多个 ChannelInboundHandler 中异步

2. ChannelPipeline 接口

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

ChannelHandler 安装到 ChannelPipeline 中的过程以下所示:oop

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

ChannelHandler 能够看做是处理往来 ChannelPipeline 事件(包括数据)的任何代码的通用容器,使事件流通过 ChannelPipeline 是 ChannelHandler 的工做,在应用程序的初始化或者引导阶段被安装。这些 ChannelHandler 接收事件、执行所实现的业务逻辑,并将数据传递给链中的下一个 ChannelHandler。它们的执行顺序由它们被添加的顺序所决定。实际上,ChannelPipeline 就是这些 ChannelHandler 的编排顺序测试

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

在 Netty 中有两种发送消息的方式,能够直接写到 Channel 中,也能够写到和 ChannelHandler 相关联的 ChannelHandlerContext 对象中。前一种方式将会致使消息从 ChannelPipeline 的尾端开始流动,后者将致使消息从 ChannelPipeline 中的下一个 ChannelHandler 开始流动


编码器和解码器

当你经过 Netty 发送或者接收一个消息时,就会发生一次数据转换。入站消息会被解码,即从字节转换成另外一种格式,一般是一个 Java 对象。若是是出站消息,则会发生相反方向的转换,从当前格式被编码为字节。为此,Netty 为编码器和解码器提供了不一样类型的抽象类,这些基类的名称将相似于 ByteToMessageDecoder 或 MessageToByteEncoder。对于一些特殊类型,可能还会有 ProtobufEncoder 和 ProtobufDecoder 这样的名称,用来支持 Google 的 Protocol Buffers

使用 Netty 提供的编码器/解码器,你会发现对于入站数据来讲,channelRead 方法/事件已经被重写。对于每一个从入站 Channel 读取的消息,将调用重写后的 channelRead 方法。随后,它将调用解码器提供的 decode() 方法,将已解码的字节转发给 ChannelPipeline 中的下一个 ChannelInboundHandler。出站消息是反过来的,编码器将消息转换为字节,并将它们转发给下一个 ChannelOutboundHandler


引导

Netty 的引导类为应用程序的网络层配置提供了容器,这涉及将一个进程绑定到某个指定的端口,或者将一个进程链接到另外一个运行在某个指定主机的指定端口上的进程。一般咱们把前面的用例称为引导一个服务器,后面的用例称为引导一个客户端。所以,有两种类型的引导:一种用于客户端(Bootstrap),而另外一种(ServerBootstrap)用于服务器

两种类型的引导类区别以下:

  • ServerBootstrap 将绑定到一个端口,由于服务器必需要监听链接,而 Bootstrap 则是由想要链接到远程节点的客户端应用程序使用

  • 引导一个客户端只须要一个 EventLoopGroup,可是一个 ServerBootstrap 则须要两个。由于服务器须要两组不一样的 Channel,第一组只包含一个 ServerChannel,表明服务器自身已绑定到某个本地端口的正在监听的套接字,而第二组将包含全部已建立的用来处理传入客户端链接的 Channel

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

相关文章
相关标签/搜索