文章目录
- Reactor反应器的IO事件的处理流程
- Netty中的Channel通道组件
- Netty中的Reactor反应器
- Netty中的Handler处理器
- Netty的流水线(pipeline)
- 第一步:
- 第二步:设置通道的IO类型
- 第三步:设置监听端口
- 第四步:设置传输通道的配置选项
- 第5步: 装配子通道的pipeline流水线
- 第六步: 开始绑定服务器新连接的监听端口
- 第7步: 自我阻塞,直到通道关闭
- 第8步: 关闭EventLoopGroup
Netty原理与基础
Netty简介
引用Netty官网的介绍
Netty是为了快速开发可维护的高性能,高可扩展,网络服务器和客户端程序而提供的异步事件驱动基础框架和工具
第一个Netty的案例实践DiscardServer
案例功能
读取客户端的输入数据,直接丢弃,不给客户端任何回复
Netty项目依赖
第一个Netty服务器端程序
Reactor反应器
反应器的作用是进行IO事件的查询和dispatch分发,Netty中的反应器组件有多种,应用场景不同,用到的反应器也各不相同,一般来说,对于多线程的JAVA Nio通信场景,Netty的反应器类型为: NioEventLoopGroup
NettyDiscardHandler
解密Netty中的Reactor反应器模式
设计模式是Java代码或者程序的重要组织方式,如果不了解设计模式,学习Java程序往往找不到头绪,所以,首先要了解Netty中的反应器模式的实现
Reactor反应器的IO事件的处理流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7o0kp6Sz-1574496521141)(78363C70968A4195AB3726B3DF01169E)]
流程分为4步:
- 通道注册: IO源于通道,IO和通道是强相关的,一个IO事件一定属于某个通道,如果想要查询通道的事件,首先要将通道注册到选择器
- 查询选择
- 事件分发
- 完成真正的IO操作和业务处理
Netty中的Channel通道组件
Channel通道组件是Netty中非常重要的组件,因为反应器模式和通道紧密相关,反应器的查询和分发的IO事件都来自于Channel通道组件
Netty对通道进行了自己的封装,在Netty中有一系列的channel通道组件,对于每一种通信协议,Netty都实现了自己的通道
Netty中的Reactor反应器
反应器模式中,一个反应器会负责一个事件处理器,不断轮询, 通过Selector选择器不断查询注册过的IO事件,则分发Handler业务处理器
Netty中的Handler处理器
Java NIO的时间类型,可供选择器监控的通道IO事件类型包括以下4种:
- 可读: OP_READ
- 可写: OP_WRITE
- 连接: OP_CONNECT
- 接收: OP_ACCEPT
Netty中,EventLoop反应器内部有一个Java NIO选择器成员 执行以上事件的查询,然后进行对应的事件分发, 事件分发(dispatch)的目标就是Netty自己的Handler处理器
Netty的Handler处理器分类
- 入站处理器: 从通道到InboundHandler入站处理器
- 出栈处理器 : 将数据写入通道
Netty的流水线(pipeline)
Netty反应器模式中各个组件之间的关系
- 反应器 和通道之间是一对多的关系
- 通道和Handler处理器实例之间,是多对多关系
通道和Handler处理器实例的绑定是如何组织?
通道的多个Handler实例
Netty设计了一个特殊的组件,叫做ChannelePipeline(通道流水线), 将绑定到一个通道的多个Handler处理器实例,穿在一起,形成一个流水线, pipeline流水线,默认被设计成一个双向链表,Handler处理器实例被包装成节点,加入到Pipeline中
入栈处理,每一个来自通道的IO事件,都会进入一次pipeline刘书贤,进入第一个Handler处理器后,IO事件会从前向后,不断流动,继续执行下一个Handler处理器
入站处理器Handler执行次序:
从前向后
出栈处理器Handler执行次序
从后向前
为了方便开发者,Netty提供Bootstrap启动器,提升开发效率
详解Bootstrap启动器类
Netty中的,有两个启动器类,分别在服务器客户端
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jYobdQYu-1574496521142)(92A7B14EE4D3489FBA076F8AA48A2F83)]
父子通道
Netty中,每一个NioSocketChannel通道所封装的是Java NIO通道,在往下就是对应到了操作系统底层的socket操作符
操作系统底层的socket操作符分为两类:
- 连接监听类型
负责接收客户独胆的套接字连接,服务器端,一个连接舰艇类型的socket描述符可以接收成千上万的传输类的socket描述符
- 传输数据类型
数据传输类的socket描述符负责传输数据,同一条tcp的socket传输链路,在服务器和客户端,都分别有一个与之对应的数据传输类型的socket描述符
EventLoopGroup线程组
Netty中,一个EventLoop相当于一个子反应器(subReactor), 一个NioEventLoop子反应器拥有一个线程,同时拥有一个Java NIO选择器
使用EventLoopGroup线程组,多个EventLoop线程组成一个EventLoopGroup线程组
Netty的EventLoopGroup线程组就是一个多线程版本的反应器,其中单个EventLoop线程对应一个子反应器(subReactor)
构造函数
构造器初始化时,会按照传入线程数量,在内部构造多个Thread线程和多个EventLoop子反应器(一个线程对应一个EventLoop子反应器) ,进行多线程的IO事件查询和分发
没有传入参数或调用无参构造函数
EventLoopGroup内部线程数为最大可用的CPU处理器的2倍,假设有4个CPU,那么会启动8个EventLoop线程,相当于8个子反应器实例(SubReactor)
Bootstrap的启动流程
Bootstrap的启动流程,也就是Netty组件的组装,配置,以及Netty服务器或客户端的使用。
创建一个服务器端的启动器实例
Bootstrap启动流程的8个步骤:
第一步:
创建反应器线程组,并赋值给ServerBootstrap启动器类实例
设置反应器线程组之前,创建两个NioEventLoopGroup线程组, 一个负责处理连接监听IO事件,名为bossLoopGroup, 另一个负责IO事件和Handler业务处理,名为workerLoopGroup
配置启动器实例
调用b.group()方法
第二步:设置通道的IO类型
Netty不仅支持 Java NIO, 也支持阻塞式OIO
第三步:设置监听端口
第四步:设置传输通道的配置选项
给父通道设置
给子通道设置:
childOption()
设置方法
第5步: 装配子通道的pipeline流水线
仅装配子通道的流水线,而不需要装配父通道的流水线
原因: 父通道也就是NioServerSocketChannel连接接收通道,内部业务处理是固定的: 接收新连接后,创建子通道,然后初始化子通道,所以不需要特别的配置,如果需要完成特殊的业务处理,可以使用ServerBootstrap的handler()方法,为父通道设置ChannelInitializer
第六步: 开始绑定服务器新连接的监听端口
b.bind()方法的功能: 返回一个端口绑定Netty的异步任务ChannelFuture, 在这里,并没有给channelFuture异步任务增加回调监听器,而是阻塞channelFuture异步任务,直到端口绑定任务执行完成
第7步: 自我阻塞,直到通道关闭
如果要阻塞当前线程直到通道关闭,可以使用通道closeFuture()方法,以获取通道关闭的异步任务,当通道关闭时,closeFuture实例的sync()方法会放回
第8步: 关闭EventLoopGroup
关闭Reactor反应器线程组,同时会关闭内部的subReactor子反应器线程,也会关闭内部的Selector选择器,内部轮询线程以及负责查询的所有子通道,在子通道关闭后,会释放底层的资源。