Netty 的学习内容主要是围绕 TCP 和 Java NIO 这两个点展开的,由于 Netty 是基于 Java NIO 的 API 之上构建的网络通讯框架,Java NIO 中的几个组件,都能在 Netty 中找到对应的封装。下面我们就来一一熟悉 Netty 中的基本组件。

一、基本组件

Netty 的组件主要有以下 8 个:

  1. Channel
  2. ByteBuf
  3. ChannelHandler
  4. ChannelHandlerContext
  5. Pipeline
  6. EventLoop
  7. EventLoopGroup
  8. ServerBootstrap/Bootstrap

1.1 Channel

  Netty 中的 Channel 封装了 JDK 中原生的 Channel,所有对 Netty 中 Channel 的操作,最后都会转化成对原生 Channel 的操作。那么为什么要封装呢,主要有两点:1. 原生的 Channel 与 Netty 框架的结构不够兼容,所有 Netty 进行了一层包装,使其更符合 Netty 使用逻辑;2. 避免了对 SocketChannel 的直接操作,提供更直观和友好的 API 给开发人员。

  Netty 常用的是 NioSocketChannel 和 NioServerSocketChannel,对应了 JDK 中的 SocketChannel 和 ServerSocketChannel。Netty 中的 Channel 都有与之对应的 EventLoop 和 Pipeline。

1.2 ByteBuf

  ByteBuf 与 JDK 中的 ByteBuffer 类似。Netty 中的 ByteBuf 有基于 ByteBuffer 构建的,也有自身设计的其他实现。从不同的层级可以有多种划分方式,使用时主要关注的可能这 3 个方面:1. 池化与非池化;2. 堆内存与直接内存;3. 是否使用了 Unsafe 类来操作内存。关于这几点暂时有个大致的了解即可。

  ByteBuffer 只使用一个指针来保存读写的索引,使用起来比较麻烦,容易出错。而 ByteBuf 则使用了两个指针分别保存当前读和写的索引,使用起来就很方便,从 ByteBuf 读取数据时,只需要关注 readerIndex 即可。将数据写入 ByteBuf 时,只需要关注 writerIndex。ByteBuff 的容量 capacity 与两个指针之间的大小关系:0 <= readerIndex <= writerIndex <= capacity。

  Netty 源码中 ByteBuf 的类注释很好的展示了它的结构:

 /*
* +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* | | (CONTENT) | |
* +-------------------+------------------+------------------+
* | | | |
* 0 <= readerIndex <= writerIndex <= capacity
*/

1.3  ChannelHandler

  ChannelHandler 简言之就是一个处理器, 它的功能就是处理消息。它就像流水线上的工人,对每一个从他面前经过的部件进行加工。与工人稍有不同的地方是,它可以什么也不做,将消息直接交给下一个处理器,也可以直接将消息丢掉,不再传递。而且 ChannelHandler 是有方向的。对于开发人员来说,就是在 ChannelHandler 中编写业务逻辑代码,需要注意的是在 Handler 中不要执行耗时较大的业务逻辑,避免影响 IO。

1.4 ChannelHandlerContext

  从名称即可知道它是 ChannelHandler 的容器,每个 ChannelHandler 都有与之一一对应的 ChannelHandlerContext 对应。实际上,每个 ChannelHandler 并不直接交互,都是通过 ChannelHandlerContext 将彼此联系起来。ChannelHandlerContext 则是一个 Node,它有前驱和后继。对于一个 Channel 来说,它看到的是一个双向链表。

1.5 Pipeline

  Pipeline 中保存了由 ChannelHandlerContext 组成的双向链表。Netty 中的每个 Channel 都有一条自己的 Pipeline,每当该通道有需要处理的消息时,就会遍历 Pipeline 中的链表,通过每一个处理器来处理消息。Pipeline 的链表中默认就保存了一个 Head  和一个 Tail,所有用户添加的处理器都在这两个节点之间。下图就是包含一个用户处理器的 Pipeline:

1.6 EventLoop

  EventLoop 可以简单的看作是一个线程,用来处理分配给它的 Channel 上的事件,也就是说一个 EventLoop 下面可能挂了多个 Channel。

1.7 EventLoopGroup

  从它的名称就可以知道它维护了一组 EventLoop,可以看作是一个 Netty 实现的线程池,负责给每一个新建里的 Channel 分配 EventLoop。

1.8 ServerBootstrap/Bootstrap

  这两个组件分别是用来启动服务端和客户端 ,在启动之前,可以通过这两个组件设定各种参数,添加 Handler,指定通道类型等。(Bootstrap 是鞋带的意思,为啥跟启动挂上勾了,可以参考知乎上的解答:Boot一词是为什么被用作计算机并作为引导解释的?或者说他的由来? - 知乎

二、Netty 线程模型

  Netty 采用的是 Reactor 线程模型,先从一个最简单的 HelloWorldServer 级别的线程模型来入手,如下图:

  先了解一个 Channel 的建立过程:

  1. 服务端启动时,会启用一个线程并创建一个 NioServerSocketChannel 来监听指定的端口。这个线程上有一个 Selector,它关注的是 Accpet 事件;
  2. 当有客户端连接过来时,上图中的 EventLoop-0会创建一个 NioSocketChannel ,将该通道注册到 EventLoop-1 的 Selector 上,然后 EventLoop-1 就负责此后该 Channel 生命周期上所有的读写事件的处理;
  3. EventLoop-1 对其所属通道数据读写及其他处理,就通过 Pipeline 中的处理器链来实现。

  Netty 还包含了普通任务和定时任务的执行。

  参考资料:

  1. 『Netty 实战』- 中文版
  2. 『Netty 权威指南』- 第二版,这本书是基于 Netty 5 写的,虽然 Netty 5 项目已经关闭了,但是本书还是值得参考的
  3. Java读源码之Netty深入剖析-慕课网实战 - 基本上对源码的分析和了解,都是基于这个视频课程的内容,讲的挺好的

Netty 基本组件与线程模型的更多相关文章

  1. 【Netty】EventLoop和线程模型

    一.前言 在学习了ChannelHandler和ChannelPipeline的有关细节后,接着学习Netty的EventLoop和线程模型. 二.EventLoop和线程模型 2.1. 线程模型 线 ...

  2. Netty高性能之Reactor线程模型

    Netty是一个高性能.异步事件驱动的NIO框架,它提供了对TCP.UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用 ...

  3. 一文弄懂-Netty核心功能及线程模型

    目录 一. Netty是什么? 二. Netty 的使用场景 三. Netty通讯示例 1. Netty的maven依赖 2. 服务端代码 3. 客户端代码 四. Netty线程模型 五. Netty ...

  4. Netty学习三:线程模型

    1 Proactor和Reactor Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发.高吞吐量的环境中进行I/O处理. I/O多路复用机制都依赖于一个事件分发器,事件 ...

  5. 深入了解Netty【五】线程模型

    引言 不同的线程模型对程序的性能有很大的影响,Netty是建立在Reactor模型的基础上,要搞清Netty的线程模型,需要了解一目前常见线程模型的一些概念. 具体是进程还是线程,是和平台或者编程语言 ...

  6. Netty源码学习(一)Netty线程模型

    给你一台4路E7-4820V2(32核心64线程),512G内存的服务器,你该如何编程才能支持百万长连接? 最直接的想法是采用BIO的模式,为每个连接新建一个线程,在一一对应的线程中直接处理连接上的数 ...

  7. Reactor 线程模型以及在netty中的应用

    这里我们需要理解的一点是Reactor线程模型是基于同步非阻塞IO实现的.对于异步非阻塞IO的实现是Proactor模型. 一 Reactor 单线程模型 Reactor单线程模型就是指所有的IO操作 ...

  8. 深入Netty逻辑架构,从Reactor线程模型开始

    本文是Netty系列第6篇 上一篇文章我们从一个Netty的使用Demo,了解了用Netty构建一个Server服务端应用的基本方式.并且从这个Demo出发,简述了Netty的逻辑架构,并对Chann ...

  9. Netty源码分析之Reactor线程模型详解

    上一篇文章,分析了Netty服务端启动的初始化过程,今天我们来分析一下Netty中的Reactor线程模型 在分析源码之前,我们先分析,哪些地方用到了EventLoop? NioServerSocke ...

随机推荐

  1. Nginx配置文件及模块解析

    一.Nginx是什么? Nginx是一个基于c语言开发的高性能http服务器及反向代理服务器.由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支支撑5万并发链接,并且cpu.内 ...

  2. Redhat 6.3上安装libssh

    遇到了很多坑,决定记录下来,有些经验还是很有帮助的. 最重要的一条就是:安装rpm包,总是比编译源码安装(make&make install)更快.记住两个rpm网站:https://pkgs ...

  3. ZYNQ DMA驱动及测试分析

    之前没有接触过DMA驱动.不了解它的原理,稍作学习先总结下dma驱动步骤: 1. 申请DMA中断. 2. 申请内存空间作为src和dts的空间. 3. 注册设备注册节点 4. 将申请到的src和dst ...

  4. 使用本机IP调试web项目

    1.查看本机IP 使用命令行查看本机ip地址: cmd 进入命令行  Ipconfig 查询本机ip. 2.找到启动项目的配置文件  启动IIS查找配置文件的位置 点击显示所有应用程序   3.修改项 ...

  5. onceAgain, 这是一个py群的群公告说明

    群规: 1. 不骚扰人 2. 不涉及娱乐政治 3. 主要就这两条 入门参考:https://book.douban.com/review/9547077/ qq群/网盘:523445644  # 加群 ...

  6. Linux c codeblock的使用(一):新建一个工程

    (1)点击New->Project,出现如下图所示,然后再选择Console application,点击Go (2)点击Next (3)根据自己的需求选择特定的语言(前提是你的系统上有这个语言 ...

  7. bzoj4700

    题解: cdq分治 先考虑没有人被秒掉的情况 代码: #include<bits/stdc++.h> #define y1 ____y1 ; using namespace std; ty ...

  8. JS的全局变量与局部变量及变量的提升

    遇到全局变量与局部变量的时候总是出一些或多或少的问题,于是专门花时间去认真研究了一下全局变量与局部变量. 这是在网上看到的一个关于全局变量与局部变量的代码,看了下作者的解析,自己也进行了研究. < ...

  9. XAMPP本地服务器打不开解决方案

    第一步:先开启相关服务:如图 第二步:在浏览器上输入localhost:端口号,(或127.0.0.1:端口号),按回车,就成功登陆本地服务器. =========================== ...

  10. 关于Servlet的一些归纳(1)

    1.servlet接口 含5个抽象放法 void init(ServletConfig config) throws ServletException //初始化Servlet void servic ...