首页 > 编程语言 >Netty源码学习3——Channel ,ChannelHandler,ChannelPipeline

Netty源码学习3——Channel ,ChannelHandler,ChannelPipeline

时间:2023-08-27 23:00:38浏览次数:41  
标签:Netty 调用 ChannelHandler ChannelPipeline EventLoop 源码 Channel

系列文章目录和关于我

零丶引入

Netty源码学习2——NioEventLoop的执行中,我们学习了NioEventLoop是如何进行事件循环以及如何修复NIO 空轮询的bug的,但是没有深入了解IO事件在netty中是如何被处理的,下面我们以服务端demo代码为例子,看下和IO事件处理密切的Channel

image-20230827172001638

如上在编写netty 服务端的时候,我们一般只需要指定Channel类型,以及实现ChannelHandler在对应方法中编写业务逻辑代码即可。

在Netty中,NioEventLoop是事件的调度中心,它控制了Io事件和其他任务的调度,但是io事件的处理是依赖ChannelHandler的,多个ChannelHandler又由ChannelPipline组装成流水线依次执行

这篇博客我们以此为切入点,看看Channel是如何初始化的,如何和EventLoop关联起来的,后续看看ChannelPipline是如何组织ChannelHandler的。

一丶Channel概述

Channel是Netty抽象出来的对网络I/O进行读写的相关接口,与JDK NIO中的Channel接口类似。Channel的主要功能有网络I/O的读写绑定端口客户端发起连接主动关闭连接获取通信双方网络地址等。

下面是NioServerSocketChannel,和NioSocketChannel的类图

image-20230827173532237
  • ChannelOutboundInvoker:定义了bind,connect,disconnect,close等方法。

  • Channel:Netty抽象出来的对网络I/O进行读写的相关接口,其中有两个关键的方法

    image-20230827174534161

    可看出EventLoop和Channel的关系——Channel是注册到EventLoop中的。

    ChannelPipeline和Channel的关系——每一个Channel会分配一个ChannelPipline。

  • AbstractChannel:Channel基本的实现,在其中有几个重要的属性:

    image-20230827175209476
    • unsafe:非jdk中的unsafe,这是netty定义的unsafe,其中定义了bind,connect等方法,在实际和网络打交道的时候会使用到
    • DefaultChannelPipeline:ChannelPipeline的默认实现,这就是Channel分配的ChannelPipline
    • EventLoop:此Channel注册到的EventLoop
  • AbstractNioChannel:使用Selector进行IO多路复用的Channel,其中有两个重要的属性

    image-20230827175848808

    从此可与看出,Netty中的Nio Channel 和 jdk中Channel的关系,它们是一对一的

    AbstractNioChannel拥有NIO的Channel,具备NIO的注册、连接等功能。但IO的读写交给了其子类。

  • AbstractNioByteChannel&AbstractNioMessageChannel

    AbstractNioByteChannel是面向字节的,通常是客户端进行使用,AbstractNioMessageChannel面向消息,通过是服务端进行使用。为什么netty这样设计昵?

    通常情况下,客户端只需要发送消息,因此直接将消息内容转换为字节流进行输出即可,这时候使用AbstractNioByteChannel更为合适。
    
    服务端在接收到客户端的消息后,需要对消息进行解码、反序列化、处理等操作,这时候使用AbstractNioMessageChannel更为合适。因为AbstractNioMessageChannel提供了方便的消息处理功能,可以对收到的字节流进行解码、转换成特定的消息对象,并提供了方便的事件驱动机制,方便开发者对消息进行处理和管理。
    
    例如,在自定义的RPC协议中,服务端需要解码和反序列化请求消息,调用相应的服务方法,并将响应消息转换为字节流输出。使用AbstractNioMessageChannel可以方便地处理这些消息读写操作,使用自定义的解码器和编码器可以将字节流转换为特定的消息对象,并且在ChannelHandler中实现业务逻辑,通过事件驱动机制方便地管理消息的读写和处理。
    
    综上所述,AbstractNioByteChannel适合用于处理字节流数据,适合用于客户端。而AbstractNioMessageChannel适合用于处理消息,适合用于服务端
    
  • NioSocketChannel

    NioSocketChannel是AbstractNioByteChannel的子类,NioSocketChannel封装了NIO中的SocketChannel,实现了IO的读写连接操作。Netty服务的每个连接都会生成一个NioSocketChannel对象

  • NioServerSocketChannel

    NioServerSocektChannel是AbstractNioMessageChannel的子类,一般是服务端进行使用,并且只负责监听Socket的接入,不关心IO读写。

二丶服务端启动是NioServerSocketChannel是如何实例化并注册到EventLoop中的

客户端的NioSocketChannel实例化和注册流程与服务端类似
image-20230827183358838

如上代码中,服务端指定了Channel类型,然后调用bind方法,在bind方法中会进行Channel的初始化+注册到EventLoop中

image-20230827183607939

1.NioServerSocketChannel的实例化

在不指定ChannelFactory的时候,这里默认是ReflectiveChannelFactory,如同其名称一样,ReflectiveChannelFactory会使用反射的方式构建出Channel

image-20230827184150871

随后会使用SelectorProvider#openServerSocketChannel创建出一个jdk原生的ServerSocketChannel。

然后调用父类构造器,设置Channel为非阻塞,并调用newUnsafe和newChannelPipeline实例化unsafe和channelPipeline

image-20230827184557990

对于服务端来说这里newUnsafe产生的是NioMessageUnsafe,ChannelPipeline通常使用的是DefaultChannelPipeline

2.NioServerSocketChannel的初始化

image-20230827185312380

初始化会将我们在ServerBootStrap中设置的参数设置到NioServerSocketChannel中

并向ChannelPipeline添加一个ServerBootstrapAcceptor,ServerBootstrapAcceptor和Netty的reactor模式有关,此类的作用后续进行学习。

3.NioServerSocketChannel的注册

随后会使用ServerBootStrap中的EventLoopGroup#register方法进行注册,这里的使用的EventLoopGroup是demo中指定的bossGroup

image-20230827185813543

因为在Reactor模式中,bossGroup负责处理ACCEPT事件,单线程使用Selector监听多路IO的Accept事件,然后将这些套接字交给上面的WorkerGroup,so这里NioServerSocketChannel注册到bossGroup中

bossGroup并不会自己进行注册,而是使用next方法找到自己的小弟——EventLoop,进行注册

image-20230827190208865

这里会使用到EventExecutorChooser进行选择EventLoop,Netty自带两种策略

  • 如果EventLoopGroup中的EventLoop是2的幂次个,那么使用PowerOfTwoEventExecutorChooser

    image-20230827190446255

    它使用取模在众多EventLoop中选择一个

  • 如果EventLoopGroup中的EventLoop不是2的幂次个,那么使用GenericEventExecutorChooser,直接对EventLoop个数进行取模

选择完EventLoop后,会调用EventLoop的注册方法,最终会使用AbstractUnsafe#register,其中会先判断执行的线程是不是EventLoop线程,如果不是那么会将任务提交到EventLoop中执行,源码如下:

image-20230827190732474

注册的即将当前Channel注册到Selector,并且attachment指定为当前Channel,这样NioEventLoop在进行IO多路复用的的时候,可通过attachment方法拿到当前Channel

image-20230827191127338

注册结束后会使用ChannelPipeline触发channelRegistered事件,关于ChannelPipeline下一篇博客中进行学习。

在这一步,还会触发NioEventLoop线程的启动,进行事件循环,在一个死循环中使用Selector监听这个Channel的IO事件,并处理其他调度任务,异步任务。(如何启动NioEventLoop线程的——Netty源码学习2——NioEventLoop的执行#NioEventLoop的启动

三丶ChannelPipeline

image-20230827214728636

上面我们说到一个Channel的实例化会触发ChannelPipeline的实例化。ChannelPipeline 和 ChannelHandler 也是我们在平时应用开发的过程中打交道最多的组件,通常程序员使用Netty进行开发只需要将自己定义的ChannelHandler加入到ChannelPipeline中。

ChannelPipeline即是ChannelHandler的流水线,ChannelPipeline 可以看作是 ChannelHandler 的容器载体,它是由一组 ChannelHandler 实例组成的,内部通过双向链表将不同的 ChannelHandler 链接在一起,如下图所示。当有 I/O 读写事件触发时,ChannelPipeline 会依次调用 ChannelHandler 列表对 Channel 的数据进行拦截和处理。

image-20230827164029646

1.ChannelHandlerContext

ChannelHandlerContext 用于保存 ChannelHandler 上下文,其包含了 ChannelHandler 生命周期的所有事件,如 connect、bind、read、flush、write、close 等。

2.ChannelInboundHandler 和 ChannelOutboundHandler

在客户端与服务端通信的过程中,数据从客户端发向服务端的过程叫出站,反之称为入站。数据先由一系列 InboundHandler 处理后入站,然后再由相反方向的 OutboundHandler 处理完成后出站。

3.DefaultChannelPipeline

image-20230827215052052

DefaultChannelPipeline是netty中ChannelPipeline的默认实现,内部保存了HeadContext,和TailContext分别作为链表的头和尾

image-20230827223142192

可以看到HeadContext即是ChannelOutboundInvoker(出站处理器)也是ChannelInboundInvoker(出站处理器),这是因为网络数据写入操作的入口就是由 HeadContext 节点完成的。HeadContext 作为 Pipeline 的头结点负责读取数据并开始传递 入站事件,当数据处理完成后,数据会反方向经过各个 ChannelOutboundInvoker的处理,最终传递到 HeadContext。

而TailContext只实现了ChannelInboundInvoker,它是最后一个ChannelInboundInvoker,用于结束入站事件的传播。

4.ChannelInboundHandler&ChannelOutboundHandler

二者都是ChannelHandler的子接口,其方法的声明对于了Netty中对事件的抽象

image-20230827224300434

4.1 ChannelInboundHandler

方法名&事件
channelRegistered 当Channel注册到它的EventLoop并且能够处理I/O时调用
channelUnregistered 当Channel从它的EventLoop中注销并且无法处理任何I/O时调用
channelActive 当Channel处理于活动状态时被调用
channelInactive 不再是活动状态且不再连接它的远程节点时被调用
channelReadComplete 当Channel上的一个读操作完成时被调
channelRead 当从Channel读取数据时被调用
channelWritabilityChanged 当Channel的可写状态发生改变时被调用
userEventTriggered 当ChannelInboundHandler.fireUserEventTriggered()方法被调用时触发

4.2 ChannelOutBoundHandler

方法名&事件
bind 当请求将Channel绑定到本地地址时被调用
connet 当请求将Channel连接到远程节点时被调用
disconnect 当请求将Channel从远程节点断开时调用
close 当请求关闭Channel时调用
deregister 当请求将Channel从它的EventLoop注销时调用
read 当请求从Channel中读取数据时调用
flush 当请求通过Channel将入队数据冲刷到远程节点时调用
write 当请求通过Channel将数据写入远程节点时被调用

四丶总结

此篇初探了Channel,ChannelPipeline,ChannelContext,ChannelHandler之间的关系,深入学习了Netty中的Nio Channel是怎么和jdk中的Channel组织起来的。

上面我们说到在Netty中,NioEventLoop是事件的调度中心,它控制了Io事件和其他任务的调度,但是io事件的处理是依赖ChannelHandler的,多个ChannelHandler又由ChannelPipline组装成流水线依次执行

那么一个网络请求在Netty中是怎么从NioEventLoop事件循环中交由ChannelPipline进行事件传播与处理的昵?这个下篇中进行学习和总结。

标签:Netty,调用,ChannelHandler,ChannelPipeline,EventLoop,源码,Channel
From: https://www.cnblogs.com/cuzzz/p/17661053.html

相关文章

  • kubernetes client-go快速入门及源码阅读
    client-go是kubernetes官方维护的一个go语言客户端,用于与k8s集群交互,使用client-go可以很方便的完成k8s的二次开发(似乎也必不可少),无论是稳定性还是健壮性都有充分的保障。client-go代码版本:v0.20.2个人水平有些,一定会出现不严谨或者错误的地方,如有错误麻烦评论指正,谢谢版......
  • 食品销售管理系统-计算机毕业设计源码+LW文档
    摘要随着时代的发展,电子商务已经遍布了我们生活的每一个角落,尤其是在移动互联网迅速发展的今天,网上购物基本已经成为了人们生活中的一部分,为了让购物变得更加的方便快捷我们通过Java语言和SpringBoot框架开发了本次的食品销售管理系统。食品销售管理系统从实际情况出发,结合当前......
  • B2C电商综合品类平台设计与实现-计算机毕业设计源码+LW文档
    B2C电商综合品类平台设计与实现-计算机毕业设计源码+LW文档摘 要随着信息技术的发展,基于web模式的购物系统逐渐普及,网上购物是一种新型的商务模式,其工作流程和经营模式受到了欢迎。电子商务可以适应现代化快节奏的生活方式,满足各类人群足不出户的在线购物,利用商城使得买卖双方......
  • 基于spark招生系统的设计与实现-计算机毕业设计源码+LW文档
    基于spark招生系统的设计与实现-计算机毕业设计源码+LW文档摘要随着高校的发展,教育改革的深入推进,高考学生数量越来越多。高考志愿管理逐渐成为高校管理必不可少的组成部分。高考志愿包括高校信息、专业信息、招生信息等,管理员和教务部门需要耗费大量的精力来管理高考志愿信息,严重......
  • 蛋糕甜品商城系统-计算机毕业设计源码+LW文档
    摘要随着信息技术的发展,基于web模式的购物系统逐渐普及,网上购物是一种新型的商务模式,其工作流程和经营模式受到了欢迎。电子商务可以适应现代化快节奏的生活方式,满足各类人群足不出户的在线购物,利用商城使得买卖双方完成线上交易,提高了购买效率。因此,开发一个适合商品在线选购的......
  • 高校奖学金管理系统的设计与实现-计算机毕业设计源码+LW文档
    摘要随着信息技术的发展,管理系统越来越成熟,各种企事业单位使用各种类型的管理系统来提高工作效率,从而降低手工操作的弊端。我国政府一直以来都非常重视高校教育的发展,近几年来高校学生人数逐渐增加,对高校奖助学金的需求越来越多。因此,通过开发高校奖助学金管理系统来提高办理效率......
  • 知识付费网站源码-包定制+开发+维护+全包上线,数字化时代下的教育转型策略与兔知云课堂
    我是木头,一名从事教育行业软件设计研发的工作者。2020年,受疫情影响,数字化升级成为了教育企业关注的焦点。如何实现培训机构的数字化转型,成为业界热议的话题。笔者将在本文中分享一些有关数字化转型的实用建议,同时也会隐晦地插入兔知云课堂的低成本音视频课程点播系统,网址为https:/......
  • 基于Springboot的宜居酒店管理系统的设计与实现-计算机毕业设计源码+LW文档
    摘要信息化的迅速发展,对人们的衣食住行产生了很大影响。越来越多的人习惯并依赖于通过信息技术和智能化的形式来处理日常各类事物。为了满足管理者管理酒店的需要,以及适应现代化酒店管理的需求,决定开发宜居酒店管理系统。帮助管理员快速的在线管理,提高了效率。本系统是选择面向......
  • 旅游管理系统的设计与实现-计算机毕业设计源码+LW文档
    摘要随着社会经济的发展,各行业竞争激烈,年轻群体工作压力大,越来越多的人希望通过旅游来缓解压力。而传统的旅行社都是通过事先定制的线路和固定时间,没有个性化定制服务,不能满足现代用户的需求。对于此,开发旅游管理系统可以很好的解决用户个性化旅游的服务,通过系统查询各种景点信息,......
  • 跨地区协同办公的公司OA的设计与实现-计算机毕业设计源码+LW文档
    1.1研究背景随着企业规模的发展,公司业务越来越多,考勤和人员的管理也变得越来越困难。在传统的考勤管理中,公司往往通过大量的人力和物力进行管理,通过手工记录考勤,统计员工信息。这种传统的管理方法容易出错,而且不能适应现代化、信息化的发展过程。因此,决定在Java编程语言的基础上,开......