一、概要
在上一篇文章讲到Dotnetty的基本认识,本文这次会讲解dotnetty非常核心的模块是属于比较硬核的干货了,然后继续往下讲解如何根据自己的需求或者自己的喜好去配置Dotnetty而不是生搬硬套官网的示例源码。如果看了本文有收获的话麻烦关注一下文章尾部的公众号和技术讨论群。各位的支持是对我莫大的帮助。
二、简介
主要讲解一下几个知识点:
- EventLoopGroup & EventLoop
- Bootstrap
- Channel
- ChannelPipeline & ChannelHandler
- ChannelHandlerContext
- ChannelHandler
三、详细内容
服务端启动引导类Bootstrap
1.EventLoopGroup & EventLoop
- 高性能RPC框架的3个要素:IO模型、数据协议、线程模型
- 假设EventLoop是一个线程,1个EventLoop可以服务多个Channel,1个Channel只有一个EventLoop可以创建多个 EventLoop 来优化资源利用,也就是EventLoopGroup。
- EventLoopGroup 负责分配 EventLoop 到新创建的 Channel,里面包含多个EventLoop
- EventLoopGroup →多个 EventLoop ,EventLoop →维护一个 Selector。
Dotnetty源码:
2.服务器启动引导类:ServerBootstrap
Group :设置线程组模型,Reactor线程模型对比EventLoopGroup
-
单线程
-
多线程
-
主从线程
Channel:设置channel通道类型NioServerSocketChannel、OioServerSocketChannel
Option: 作用于每个新建立的channel,设置TCP连接中的一些参数,如下:
-
ChannelOption.SO_BACKLOG: 存放已完成三次握手的请求的等待队列的最大长度;
-
ChannelOption.TCP_NODELAY: 为了解决Nagle的算法问题,默认是false, 要求高实时性,有数据时马上发送,就将该选项设置为true关闭Nagle算法;如果要减少发送次数,就设置为false,会累积一定大小后再发送。
-
ChildOption: 作用于被accept之后的连接
-
ChildHandler: 用于对每个通道里面的数据处理
3.连接通道类:Channel
Channel: 客户端和服务端建立的一个连接通道(可以理解为一个channel就是一个socket连接) ChannelHandler: 负责Channel的逻辑处理 ChannelPipeline: 负责管理ChannelHandler的有序容器
关系: 一个Channel包含一个ChannelPipeline,所有ChannelHandler都会顺序加入到ChannelPipeline中 创建 Channel时会自动创建一个ChannelPipeline,每个Channel都有一个管理它的pipeline,这关联是永久 性的Channel当状态出现变化,就会触发对应的事件。
生命周期:
-
ChannelRegistered: channel注册到一个EventLoop
-
ChannelActive: 变为活跃状态(连接到了远程主机),可以接受和发送数据
-
ChannelInactive: channel处于非活跃状态,没有连接到远程主机
-
ChannelUnregistered: channel已经创建,但是未注册到一个EventLoop里面,也就是没有和Selector绑定
4.频道的内部实现 ChannelHandler & ChannelPipeline
-
ChannelInboundHandler:(入站) 处理输入数据和Channel状态类型改变,适配器。
-
ChannelInboundHandlerAdapter(适配器设计模式) 常用的:SimpleChannelInboundHandler
-
ChannelOutboundHandler:(出站) 处理输出数据,适配器 ChannelOutboundHandlerAdapter
-
ChannelPipeline: 好比厂里的流水线一样,可以在上面添加多个ChannelHanler,也可看成是一串
-
ChannelHandler 实例,拦截穿过 Channel 的输入输出 event, ChannelPipeline 实现了拦截器的一种高级形式,使得用户可以对事件的处理以及ChannelHanler之间交互获得完全的控制权。
5.频道的内部实现 ChannelHandler & ChannelPipeline
ChannelHandlerContext是连接ChannelHandler和ChannelPipeline的桥梁,ChannelHandlerContext部分方法和Channel及ChannelPipeline重合。
- 好比调用write方法Channel、ChannelPipeline、ChannelHandlerContext 都可以调用此方法,前两者都会在整个管道流里 传播,而ChannelHandlerContext就只会在后续的Handler里面传播。
- AbstractChannelHandlerContext类双向链表结构,next/prev分别是后继节点,和前驱节点。
- DefaultChannelHandlerContext 是实现类,但是大部分都是父类那边完成,这个只是简单的实现一些方法 主要就是判断Handler的类型。
- ChannelInboundHandler之间的传递,主要通过调用Context 里面的FireXXX()方法来实现下个handler的调用。
6.Handler执行顺序
一般的项目中,inboundHandler和outboundHandler有多个,在Pipeline中的执行顺序?
InboundHandler顺序执行,OutboundHandler逆序执行
- InboundHandler顺序执行,OutboundHandler逆序执行
- InboundHandler之间传递数据,通过context.fireChannelRead(message)
- InboundHandler通过context.write(message),则会传递到outboundHandler
- 使用context.write(message)传递消息,Inbound需要放在结尾,在Outbound之后,不然outboundhandler会不执行; 但是使用channel.write(message)、pipline.write(message)情况会不一致,都会执行。
- OutBound和Inbound谁先执行,针对客户端和服务端而言,客户端是发起请求再接受数据,先outbound再 inbound,服务端则相反。
希望大家多多支持。不胜感激。
- E-Mail:zhuzhen723723@outlook.com
- QQ: 580749909(个人群)
- Blog: https://www.cnblogs.com/justzhuzhu/
- Git: https://github.com/JusterZhu
- 微信公众号