当前位置: 首页 > news >正文

Netty笔记6:Netty组件

Netty笔记1:线程模型

Netty笔记2:零拷贝

Netty笔记3:NIO编程

Netty笔记4:Epoll

Netty笔记5:Netty开发实例

Netty笔记6:Netty组件

Netty笔记7:ChannelPromise通知处理

Netty笔记8:ByteBuf使用介绍

Netty笔记9:粘包半包

Netty笔记10:LengthFieldBasedFrameDecoder

Netty笔记11:编解码器

Netty笔记12:模拟Web服务器

Netty笔记13:序列化

文章目录

  • EventLoop
  • ChannelHandler生命周期
  • ChannelPiple与ChannelHandler
    • ChannelHandlerContext
    • ChannelHandler
      • ChannelInboundHandler
      • ChannelOutboundHandler
      • HandlerAdapter
    • 共享Handler

Bootstrap:是Netty框架的启动类和主入口类,分为客户端(Bootstrap)和服务器端(ServerBootstrap)两种。

EventLoop:可以看成一个线程,我们的那些操作都是在这个上面执行;

EventLoopGroup:线程组,管理EventLoop的;

NioSocketChannel/NioServerSocketChannelchannel是NIO中的基本构造,所以在Netty中,自然也有;

ChannelHandler:事件用于通知Netty改变状态,触发对应处理器,如连接激活、读取、错误等这些事件,都会分给ChannelHander处理,我们只需要实现对应的方法,就行;Netty也定义了一些预定义好的实现,包括各种协议(如Http,SSL/TLS)的ChannelHandler

ChannelPiple:每个Channel都有自己的ChannelPiple,作为ChannelHandler的容器,从网络到业务处理,再到网络,也就是从入站到出站,业务处理都是在piple中流转,Handler执行的顺序也是他们被添加的顺序。

ChannelFutureNetty中的所有操作都是异步的,它实现于JDK中的Future

EventLoop

在当前的线程模型中,它可能有多个Channel共享,这使得可以通过尽可能少的Thread支撑大量的Channel;

EventLoopGroup负责每个新创建的Channel分配一个EventLoop,一旦Channel被分配给了EventLoop,那么他们关系会延续到这个Channel关闭销毁;

需要注意的一点:因为多个Channel共享一个EventLoop,也就是一个线程,那么ThreadLocal遍历也是共享。

ChannelHandler生命周期

ChannelHandler被添加到ChannelPiple中或者被从ChannelPiple中移除会调用下面的方法,并且都会接受一个ChannelHandlerContext的参数:

  • handlerAdded:channelHandler添加时被调用;
  • handlerRemoved:被移除时调用;
  • exceptionCaught:产生错误时调用;

ChannelPiple与ChannelHandler

ChannelPiple其实是以双向链表的形式进行维护和管理。

之前提到过出站入站,就是数据从网络到达piple,为入站,数据从piple出去到网络,为出站,出入站均有对应的事件handler处理,并且,如果业务没有特殊要求,可以不用区分出入站的handler

ChannelHandlerContext

ChannelHandlerChannelPiple传递的上下文对象,更像是链表中的node对象,它对数据进行了保证,并且包含prenext传递Handler

当添加ChannelHandle时,ChannelPiple都会创建一个ChannelHandlerContext,而handler呈链表形式,并不是handlerhandler间是链表结构,它本身是处理器,不应有链表的形式,所以,就有我们的ChannelHandlerContext来管理链表,它具有prenext,所以只要通过context就可以找到下一个handler

ChannelHandler

我们的业务就写在这ChannelHandler下;

它有两个重要的子接口:

  • ChannelInboundHandler:处理入站数据以及各种状态变化,从handler列表头部开始执行,addLast的顺序
  • ChanneloutboundHandler:处理出站数据并且允许拦截所有的操作,从handler列表尾部开始执行,addLast的逆序;

注意:他们的执行顺序,他们通过addLast添加的方式一样,但是执行顺序是相反的。

ChannelInboundHandler

// 当channel已经注册到EventLoop,并能够处理IO时调用  
void channelRegistered(ChannelHandlerContext var1) throws Exception;
// 当Channel从它的EventLoop注销并且无法处理任何IO时被调用
    void channelUnregistered(ChannelHandlerContext var1) throws Exception;
// 当channel处于活动状态时被调用;channel已经连接/绑定并且已经就行;
    void channelActive(ChannelHandlerContext var1) throws Exception;
// 当channel离开活动状态并且不再连接它的原出处节点时被调用
    void channelInactive(ChannelHandlerContext var1) throws Exception;
// 当channel读取数据时调用
    void channelRead(ChannelHandlerContext var1, Object var2) throws Exception;
// 当channel的读操作完成时调用
    void channelReadComplete(ChannelHandlerContext var1) throws Exception;
// 当方法fireUserEvnetTriggered()被调用时调用
    void userEventTriggered(ChannelHandlerContext var1, Object var2) throws Exception;
// 当channel可写状态发生改变时被调用,可通过调用channel的isWriteable()方法检测channel是否可写
    void channelWritabilityChanged(ChannelHandlerContext var1) throws Exception;
// 当出现异常时调用
    void exceptionCaught(ChannelHandlerContext var1, Throwable var2) throws Exception;

ChannelOutboundHandler

// 当请求将channel绑定到本地地址时被调用  
void bind(ChannelHandlerContext var1, SocketAddress var2, ChannelPromise var3) throws Exception;
// 当将channel连接到远程节点时被调用
    void connect(ChannelHandlerContext var1, SocketAddress var2, SocketAddress var3, ChannelPromise var4) throws Exception;
// 当将channel从远程节点断开时被调用
    void disconnect(ChannelHandlerContext var1, ChannelPromise var2) throws Exception;
// 当请求关闭channel时被调用
    void close(ChannelHandlerContext var1, ChannelPromise var2) throws Exception;
// 当请求将channel从EventLoop注销时被调用
    void deregister(ChannelHandlerContext var1, ChannelPromise var2) throws Exception;
// 当从channel读取数据时被调用
// 注意,他是发出读数据的请求,不是读数据
    void read(ChannelHandlerContext var1) throws Exception;
// 当请求通过channel写数据到远程节点时被调用
    void write(ChannelHandlerContext var1, Object var2, ChannelPromise var3) throws Exception;
// 当请求通过channel将入队数据冲刷到远程节点时被调用
    void flush(ChannelHandlerContext var1) throws Exception;

为什么OutHandler会有read方法,出站需要读取数据吗?

这里它并不是读取数据,而是读取数据的请求操作,Netty会将其打包成一个事件,有了事件在模式循环下被识别到,进而触发inboundHnadler,属于出站事件。(可以参考Reactor模型理解)

HandlerAdapter

对应出站入站,有ChannelOutboundHandlerAdapterChannelInboundHandlerAdapter,是Netty为我们实现的抽象类,我们可以继承它扩展我们自己的业务;

共享Handler

如果需要将handler置为全局的,也就是共享的,那么需要加上注解:@ChannelHandler.Sharable

这里要注意的是注释说明:

Indicates that the same instance of the annotated ChannelHandler can be added to one or more ChannelPipelines multiple times without a race condition.
If this annotation is not specified, you have to create a new handler instance every time you add it to a pipeline because it has unshared state such as member variables.
This annotation is provided for documentation purpose, just like the JCIP annotations .

表明同一个被注解的ChannelHandler实例可以无竞态条件地被多次添加到一个或多个ChannelPipeline中。
如果未指定此注解,则每次将其添加到管道中时都必须创建一个新的处理器实例,因为它具有未共享的状态,例如成员变量。
此注解仅用于文档目的,就像JCIP注解一样。

通过他的注释可以知道,添加这个共享注解,是可以在线程无竞争的条件下被多次使用,也就是需要保证线程安全,这是因为,如果被该注解标注的ChannelHandler中存在非线程安全的变量被使用,那么多个线程并发时,就无法保证该Channel能够正常的输出结果。

然后就是没有Sharable注解的话,每次添加都是一个新的实例,不会有问题。

相关文章:

  • 剑指 Offer II 060. 出现频率最高的 k 个数字
  • [Redis] 终极缓存四连杀:缓存预热、缓存击穿、缓存穿透、缓存雪崩,真的懂了吗?
  • XHR请求解密:抓取动态生成数据的方法
  • 【django初学者项目】
  • Unity3D 布料模拟(Cloth Simulation)详解
  • 计算机网络(1) 网络通信基础,协议介绍,通信框架
  • 【杂谈】信创电脑华为w515(统信系统)登录锁定及忘记密码处理
  • JVM简单了解
  • Avalonia 打包成deb
  • Stream流的核心思想
  • 为AI聊天工具添加一个知识系统 之130 详细设计之71 通用编程语言 之1
  • MAUI(C#)安卓开发起步
  • #define GBB_DEPRECATED_MSG(msg) __declspec(deprecated(msg))
  • VIA的寄生电感和Stub对高速信号的影响
  • 【大模型安全】大模型的技术风险
  • 【虚拟仿真】Unity3D中实现激光/射线的发射/折射/反射的效果(3D版)
  • 嵌入式L6计算机网络
  • 通信专业——初入职场的懵懂
  • 19.10、C++11新特性有哪些⑩【继承构造函数】
  • 洛谷 P1850 [NOIP 2016 提高组] 换教室(期望DP)【 提高+/省选−】
  • 纽约市长称墨海军帆船撞桥已致2人死亡,撞桥前船只疑似失去动力
  • 高飞已任南航集团党组副书记
  • 61岁云浮市律师协会副会长谭炳光因突发疾病逝世
  • 东部沿海大省浙江,为何盯上内河航运?
  • 又一例!易方达基金张坤卸任副总职务,将专注于投资管理工作
  • 王伟妻子人民日报撰文:81192,一架永不停航的战机