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 被创建时,它会被自动地分配到它专属的 ChannelPipeline

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

  • 一个 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

Netty 框架学习 —— Netty 组件与设计的更多相关文章

  1. NetCore Netty 框架 BT.Netty.RPC 系列随讲 二 WHO AM I 之 NETTY/NETTY 与 网络通讯 IO 模型之关系?

    一:NETTY 是什么? Netty 是什么?  这个问题其实百度上一搜一堆. 这是官方话的描述:Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个 ...

  2. Netty 框架学习 —— 引导

    概述 前面我们学习了 ChannelPipeline.ChannelHandler 和 EventLoop 之后,接下来的问题是:如何将它们组织起来,成为一个可实际运行的应用程序呢?答案是使用引导(B ...

  3. Netty 框架学习 —— 编解码器框架

    编解码器 每个网络应用程序都必须定义如何解析在两个节点之间来回传输的原始字节,以及如何将其和目标应用程序的数据格式做相互转换.这种转换逻辑由编解码器处理,编解码器由编码器和解码器组成,它们每种都可以将 ...

  4. Netty 框架学习 —— 第一个 Netty 应用

    概述 在本文,我们将编写一个基于 Netty 实现的客户端和服务端应用程序,相信通过学习该示例,一定能更全面的理解 Netty API 该图展示的是多个客户端同时连接到一台服务器.客户端建立一个连接后 ...

  5. Netty 框架学习 —— EventLoop 和线程模型

    EventLoop 接口 Netty 是基于 Java NIO 的,因此 Channel 也有其生命周期,处理一个连接在其生命周期内发生的事件是所有网络框架的基本功能.通常来说,我们使用一个线程来处理 ...

  6. Netty 框架学习 —— ByteBuf

    概述 网络数据的基本单位总是字节,Java NIO 提供了 ByteBuffer 作为它的字节容器,但这个类的使用过于复杂.Netty 的 ByteBuf 具有卓越的功能性和灵活性,可以作为 Byte ...

  7. Netty 框架学习 —— 单元测试

    EmbeddedChannel 概述 ChannelHandler 是 Netty 程序的关键元素,所以彻底地测试它们应该是你的开发过程中的一个标准部分,EmbeddedChannel 是 Netty ...

  8. Netty 框架学习 —— 预置的 ChannelHandler 和编解码器

    Netty 为许多提供了许多预置的编解码器和处理器,几乎可以开箱即用,减少了在烦琐事务上话费的时间和精力 空闲的连接和超时 检测空闲连接以及超时对于释放资源来说至关重要,Netty 特地为它提供了几个 ...

  9. Netty 框架学习 —— 添加 WebSocket 支持

    WebSocket 简介 WebSocket 协议是完全重新设计的协议,旨在为 Web 上的双向数据传输问题提供一个切实可行的解决方案,使得客户端和服务器之间可以在任意时刻传输消息 Netty 对于 ...

随机推荐

  1. Salesforce学习之路(一)几个简单概念

    Salesforce是一款非常强大的CRM(Customer Relationship Management)系统,国外企业使用十分频繁,而国内目前仅有几家在使用(当然,国内外企使用的依旧较多),因此 ...

  2. 《C++编程思想》部分章节学习笔记整理

    简介 此笔记为<C++编程思想>中部分章节的学习笔记,主要是第15章--多态性和虚函数 的学习笔记,此外还有少量其他章节的内容. 目录 文档:<C++编程思想>

  3. Mybatis3源码笔记(七)Plugin

    1.Mybatis3的插件其实主要是用到了责任链和动态代理两种模式相结合而生成的.下面我们看一个例子,在执行所有update操作时,执行一个小小的测试输出. @Intercepts({@Signatu ...

  4. 算法图解...pdf

    电子书资源:算法图解 书籍简介   本书示例丰富,图文并茂,以让人容易理解的方式阐释了算法,旨在帮助程序员在日常项目中更好地发挥算法的能量.书中的前三章将帮助你打下基础,带你学习二分查找.大O表示法. ...

  5. python读取excel数据为json格式(兼容xls\xlsx)

    做自动化时需要从excel读取数据: 本文实现将excel文件数据读取为json格式,方便自动化调用 读取xls文件 使用xlrd读取xls文件代码: import xlrd def read_xls ...

  6. VScode+Sublime安装与汉化

    两大常用编辑器安装与汉化 想敲代码?工欲善其事,必先利其器,先安装编写代码所需要的工具吧.本期的主角是VScode与Sublime,这是两款比较热门的代码编辑器. 目录: VScode安装与汉化 Su ...

  7. Mybatis的简单增删改查

    刚开始学习Mybatis可以先看下官方文档,MyBatis是支持定制化SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis避免了几乎所有的JDBC代码和手工设置参数以及抽取结果集.MyBat ...

  8. 解决GET http://localhost:8080/js/layui/layui.js net::ERR_ABORTED 404

    用ssm+layui在写页面的时候,发现无法找到资源路径 <script src="js/layui/layui.js" charset="utf-8"& ...

  9. 如何在spring boot中从控制器返回一个html页面?

    项目截图 解决方法 我之前用的@RestController注解,而@RestController这个控制器返回数据而不是视图,改成@Controller 就好了(以下是修改后的) @Controll ...

  10. Kafka源码分析(一) - 概述

    系列文章目录 https://zhuanlan.zhihu.com/p/367683572 目录 系列文章目录 一. 实际问题 二. 什么是Kafka, 如何解决这些问题的 三. 基本原理 1. 基本 ...