Young's blog Young's blog
首页
Spring
  • 前端文章1

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Young

首页
Spring
  • 前端文章1

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 【Netty】从 BIO、NIO 聊到 Netty
  • 【Netty】Netty组件介绍
    • 【Netty】传输(Transport)
    • 多路复用 I/O 模型详解, 为什么他能支持更高的并发
    • 万字详解!Netty经典32连问!
    • netty
    andanyang
    2023-04-03
    目录

    【Netty】Netty组件介绍

    # Netty 组件介绍

    Netty 有 Bootstrap/ServerBootstrap,Channel,EventLoop,ChannelFuture, ChannelHandler,ChannelPipeline,编码器和解码器等核心组件。

    # Bootstrap/ServerBootstrap

    Bootstrap 和 ServerBootstrap 是 Netty 应用程序的引导类,它提供了用于应用程序网络层的配置。 一般的 Netty 应用程序总是分为客户端和服务端,所以引导分为客户端引导 Bootstrap 和服务端引导 ServerBootstrap, ServerBootstrap 作为服务端引导,它将服务端进程绑定到指定的端口,而 Bootstrap 则是将客户端连接到 指定的远程服务器。 Bootstrap 和 ServerBootstrap 除了职责不同,它们所需的 EventLoopGroup 的数量也不同, Bootstrap 引导客户端只需要一个 EventLoopGroup,而 ServerBootstrap 则需要两个 EventLoopGroup。

    Bootstrap引导类功能

    # Channel

    在我们使用某种语言,如 c/c++,java,go 等,进行网络编程的时候,我们通常会使用到 Socket, Socket 是对底层操作系统网络 IO 操作(如 read,write,bind,connect 等)的封装, 因此我们必须去学习 Socket 才能完成网络编程,而 Socket 的操作其实是比较复杂的,想要使用好它有一定难度, 所以 Netty 提供了 Channel(io.netty.Channel,而非 java nio 的 Channel),更加方便我们处理 IO 事件。

    # EventLoop

    EventLoop 用于服务端与客户端连接的生命周期中所发生的事件。 EventLoop 与 EventLoopGroup,Channel 的关系模型如下:

    EventLoop模型

    一个 EventLoopGroup 通常包含一个或多个 EventLoop,一个 EventLoop 可以处理多个 Channel 的 IO 事件, 一个 Channel 也只会被注册到一个 EventLoop 上。在 EventLoop 的生命周期中,它只会和一个 Thread 线程绑定,这个 EventLoop 处理的 IO 事件都将在与它绑定的 Thread 内被处理。

    # ChannelFuture

    在 Netty 中,所有的 IO 操作都是异步执行的,所以一个操作会立刻返回,但是如何获取操作执行完的结果呢? Netty 就提供了 ChannelFuture 接口,它的 addListener 方法会向 Channel 注册 ChannelFutureListener, 以便在某个操作完成时得到通知结果。

    # ChannelHandler

    我们知道 Netty 是一个款基于事件驱动的网络框架,当特定事件触发时,我们能够按照自定义的逻辑去处理数据。 ChannelHandler 则正是用于处理入站和出站数据钩子,它可以处理几乎所有类型的动作,所以 ChannelHandler 会是 我们开发者更为关注的一个接口。

    ChannelHandler 主要分为处理入站数据的 ChannelInboundHandler 和出站数据的 ChannelOutboundHandler 接口。

    ChannelHandler接口层次图

    Netty 以适配器的形式提供了大量默认的 ChannelHandler 实现,主要目的是为了简化程序开发的过程,我们只需要 重写我们关注的事件和方法就可以了。 通常我们会以继承的方式使用以下适配器和抽象:

    • ChannelHandlerAdapter
    • ChannelInboundHandlerAdapter
    • ChannelDuplexHandler
    • ChannelOutboundHandlerAdapter

    # ChannelPipeline

    上面介绍了 ChannelHandler 的作用,它使我们更关注于特定事件的数据处理,但如何使我们自定义的 ChannelHandler 能够在事件触发时被使用呢? Netty 提供了 ChannelPipeline 接口,它 提供了存放 ChannelHandler 链的容器,且 ChannelPipeline 定义了在这条 ChannelHandler 链上 管理入站和出站事件流的 API。 当一个 Channel 被初始化时,会使用 ChannelInitializer 接口的 initChannel 方法在 ChannelPipeline 中 添加一组自定义的 ChannelHandler。

    # 入站事件和出站事件的流向

    从服务端角度来看,如果一个事件的运动方向是从客户端到服务端,那么这个事件是入站的,如果事件运动的方向 是从服务端到客户端,那么这个事件是出站的。

    Netty出站入站

    上图是 Netty 事件入站和出站的大致流向,入站和出站的 ChannelHandler 可以被安装到一个 ChannelPipeline 中, 如果一个消息或其他的入站事件被[读取],那么它会从 ChannelPipeline 的头部开始流动,并传递给第一个 ChannelInboundHandler ,这个 ChannelHandler 的行为取决于它的具体功能,不一定会修改消息。 在经历过第一个 ChannelInboundHandler 之后, 消息会被传递给这条 ChannelHandler 链的下一个 ChannelHandler,最终消息会到达 ChannelPipeline 尾端,消息的读取也就结束了。

    数据的出站(消息被[写出])流程与入站是相似的,在出站过程中,消息从 ChannelOutboundHandler 链的尾端开始流动, 直到到达它的头部为止,在这之后,消息会到达网络传输层进行后续传输。

    # 进一步了解 ChannelHandler

    鉴于入站操作和出站操作是不同的,可能有同学会疑惑:为什么入站 ChannelHandler 和出站 ChannelHandler 的数据 不会窜流呢(为什么入站的数据不会到出站 ChannelHandler 链中)? 因为 Netty 可以区分 ChannelInboundHandler 和 ChannelOutboundHandler 的实现,并确保数据只在两个相同类型的 ChannelHandler 直接传递,即数据要么在 ChannelInboundHandler 链之间流动,要么在 ChannelOutboundHandler 链之间流动。

    当 ChannelHandler 被添加到 ChannelPipeline 中后,它会被分配一个 ChannelHandlerContext, 它代表了 ChannelHandler 和 ChannelPipeline 之间的绑定。 我们可以使用 ChannelHandlerContext 获取底层的 Channel,但它最主要的作用还是用于写出数据。

    # 编码器和解码器

    当我们通过 Netty 发送(出站)或接收(入站)一个消息时,就会发生一次数据的转换,因为数据在网络中总是通过字节传输的, 所以当数据入站时,Netty 会解码数据,即把数据从字节转为为另一种格式(通常是一个 Java 对象), 当数据出站时,Netty 会编码数据,即把数据从它当前格式转为为字节。

    Netty 为编码器和解码器提供了不同类型的抽象,这些编码器和解码器其实都是 ChannelHandler 的实现, 它们的名称通常是 ByteToMessageDecoder 和 MessageToByteEncoder。

    对于入站数据来说,解码其实是解码器通过重写 ChannelHandler 的 read 事件,然后调用它们自己的 decode 方法完成的。 对于出站数据来说,编码则是编码器通过重写 ChannelHandler 的 write 事件,然后调用它们自己的 encode 方法完成的。

    为什么编码器和解码器被设计为 ChannelHandler 的实现呢?

    我觉得这很符合 Netty 的设计,上面已经介绍过 Netty 是一个事件驱动的框架,其事件由特定的 ChannelHandler 完成,我们从用户的角度看,编码和解码其实是属于应用逻辑的,按照应用逻辑实现自定义的编码器和解码器就是 理所应当的。

    # SimpleChannelInboundHandler

    在我们编写 Netty 应用程序时,会使用某个 ChannelHandler 来接受入站消息,非常简单的一种方式 是扩展 SimpleChannelInboundHandler< T >,T 是我们需要处理消息的类型。 继承 SimpleChannelInboundHandler 后,我们只需要重写其中一个或多个方法就可以完成我们的逻辑。

    编辑 (opens new window)
    上次更新: 2024/04/19, 08:52:45
    【Netty】从 BIO、NIO 聊到 Netty
    【Netty】传输(Transport)

    ← 【Netty】从 BIO、NIO 聊到 Netty 【Netty】传输(Transport)→

    最近更新
    01
    idea 热部署插件 JRebel 安装及破解,不生效问题解决
    04-10
    02
    spark中代码的执行位置(Driver or Executer)
    12-12
    03
    大数据技术之 SparkStreaming
    12-12
    更多文章>
    Theme by Vdoing | Copyright © 2019-2024 Young | MIT License
    浙ICP备20002744号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式