> 文档中心 > Netty学习之Channel组件

Netty学习之Channel组件


从高层次的角度来看,Netty 解决了两个相应的关注领域,我们可将其大致标记为技术的和体系结构的。首先,它的基于 Java NIO
的异步的和事件驱动的实现,保证了高负载下应用程序性能的最大化和可伸缩性。其次,Netty
也包含了一组设计模式,将应用程序逻辑从网络层解耦,简化了开发过程,同时也最大限度地提高了可测试性、模块化以及代码的可重用性。

Netty组件详解

    • Channel 接口
    • EventLoop 接口
    • ChannelFuture 接口
    • ChannelHandler 和 ChannelPipeline
      • ChannelHandler 接口
      • ChannelPipeline 接口

接下来将对 ChannelEventLoopChannelFuture 类进行的讨论增添更多的细节,这些类合在一起,可以被认为是 Netty 网络抽象的代表:
 Channel—Socket;
 EventLoop—控制流、多线程处理、并发;
 ChannelFuture—异步通知。

Channel 接口

基本的 I/O 操作(bind()、connect()、read()和 write())依赖于底层网络传输所提
供的原语。在基于 Java 的网络编程中,其基本的构造是 class Socket。Netty 的 Channel 接
口所提供的 API,大大地降低了直接使用 Socket 类的复杂性。此外,Channel 也是拥有许多
预定义的、专门化实现的广泛类层次结构的根,下面是一个简短的部分清单:

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

EventLoop 接口

EventLoop 定义了 Netty 的核心抽象,用于处理连接的生命周期中所发生的事件。我们将
结合 Netty 的线程处理模型的上下文对 EventLoop 进行详细的讨论。目前,图 3-1
在高层次上说明了 Channel、EventLoop、Thread 以及 EventLoopGroup 之间的关系。
Netty学习之Channel组件

  1. 一个 EventLoopGroup 包含一个或者多个 EventLoop
  2. 一个 EventLoop 在它的生命周期内只和一个 Thread 绑定;
  3. 所有由 EventLoop 处理的 I/O 事件都将在它专有的 Thread 上被处理;
  4. 一个 Channel 在它的生命周期内只注册于一个 EventLoop;
  5. 一个 EventLoop 可能会被分配给一个或多个 Channel。

注意,在这种设计中,一个给定 Channel 的 I/O 操作都是由相同的 Thread 执行的,实际
上消除了对于同步的需要。

ChannelFuture 接口

正如我们已经解释过的那样,Netty 中所有的 I/O 操作都是异步的。因为一个操作可能不会
立即返回,所以我们需要一种用于在之后的某个时间点确定其结果的方法。为此,Netty 提供了
ChannelFuture 接口,其 addListener()方法注册了一个 ChannelFutureListener,以
便在某个操作完成时(无论是否成功)得到通知。
关于 ChannelFuture 的更多讨论
可以将 ChannelFuture 看作是将来要执行的操作的结果的
占位符。它究竟什么时候被执行则可能取决于若干的因素,因此不可能准确地预测,但是可以肯
定的是它将会被执行。此外,所有属于同一个 Channel 的操作都被保证其将以它们被调用的顺序
被执行。
我们将在后面深入地讨论 EventLoop 和 EventLoopGroup。

ChannelHandler 和 ChannelPipeline

ChannelHandler 接口

从应用程序开发人员的角度来看,Netty 的主要组件是 ChannelHandler,它充当了所有
处理入站和出站数据的应用程序逻辑的容器。这是可行的,因为 ChannelHandler 的方法是
由网络事件(其中术语“事件”的使用非常广泛)触发的。事实上,ChannelHandler 可 专
门用于几乎任何类型的动作,例如将数据从一种格式转换为另外一种格式,或者处理转换过程
中所抛出的异常。
举例来 说,ChannelInboundHandler 是一个你将会经常实现的子接口。这种类型的
ChannelHandler 接收入站事件和数据,这些数据随后将会被你的应用程序的业务逻辑所处
理。当你要给连接的客户端发送响 应时,也可以从 ChannelInboundHandler 冲刷数据。你
的应用程序的业务逻辑通常驻留在一个或者多个 ChannelInboundHandler 中。

ChannelPipeline 接口

ChannelPipeline 提供了 ChannelHandler 链的容器,并定义了用于在该链上传播入站
和出站事件流的 API。当 Channel 被创建时,它会被自动地分配到它专属的 ChannelPipeline
ChannelHandler 安装到 ChannelPipeline 中的过程如下所示:

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

为了审查发送或者接收数据时将会发生什么,让我们来更加深入地研究 ChannelPipeline
ChannelHandler 之间的共生关系吧。
ChannelHandler 是专为支持广泛的用途而设计的,可以将它看作是处理往来 Channel-Pipeline 事件(包括数据)的任何代码的通用容器。图 3-2 说明了这一点,其展示了从 ChannelHandler 派生的 ChannelInboundHandlerChannelOutboundHandler 接口。

鉴于出站操作和入站操作是不同的,你可能会想知道如果将两个类别的 ChannelHandler都混合添加到同一个 ChannelPipeline 中会发生什么。虽 然 ChannelInboundHandleChannelOutboundHandle 都扩展自 ChannelHandler,但是 Netty 能区分 ChannelIn-boundHandler 实现和 ChannelOutboundHandler 实现,并确保数据只会在具有相同 定向类型的两 个 ChannelHandler 之间传递。当ChannelHandler 被添加到ChannelPipeline 时,它将会被分配一个ChannelHandler-Context,其代表了 ChannelHandler 和 ChannelPipeline 之间的绑定。虽然这个对象可以被用于获取底层的 Channel,但是它主要还是被用于写出站数据。在 Netty 中,有两种发送消息的方式。你可以直接写到 Channel 中,也可以 写到和 Channel-Handler相关联的ChannelHandlerContext对象中。前一种方式将会导致消息从Channel-
Pipeline 的尾端开始流动,而后者将导致消息从 ChannelPipeline 中的下一个 Channel-Handler 开始流动。

旅游攻略大全