netty 协议/流程
HTTP(超文本传输协议) 建立在TCP传输协议之上的应用层协议。Netty的HTTP协议栈时基于NIO通信框架开发,Netty的HTTP协议也是一异步非阻塞。 // servlet 是在3.0 引入正式的非阻塞。对应tomcat 8.0 。
WebSocket
是HTML5 提供的一种全双工通信技术
被IETF定位标准的RFC6455、WebSocket API 被W3C定为标准。WebSocket API 中浏览器和 服务器只需要一个握手动作,让后,浏览器和服务器之间形成了一条快速通道。两者可以直接互相传输数据。WebSocket 基于 TCP双向全工进行消息传递
相比,HTTP的半双工协议
性能得到了很大提升。
- WebSocket 的特点
- 单一的TCP链接,采用全双工模式通信
- 对代理,防火墙和路由透明
- 无头部信息、Cookie身份验证
- 无安全开销
- 通过 ping/pong 帧保持链路激活
- 服务器可以主动传递消息给客户端,不在需要客户端轮询。
服务端流程
- 创建
ServerBootstrap
实例。ServerBootstrap是Netty服务端端启动辅助类,它提供了一系列的方法用于设置服务启动相关参数。底层通过门面模式对各种能力进行抽象和封装,不要用户跟过多的底层API打交道,以降低用户的开发难度。 - 设置并绑定
Reactor
线程池。Netty 的Reactor 先吃池是EventLoopGroup
,它实际是EventLoop
的数组。EventLoop
的职责是处理所有注册到本线程多路复用起Selector
上的Channel,Selector
的轮询操作由绑定的EventLoop
线程run 方法驱动,在一个循环体内循环执行。EventLoop
的职责不仅仅是处理网络 I/O 事件,用户自定义的 Task 和定时任务 Task 也统一由EventLoop
线程中在启动其他类型的线程用于异步执行另外的任务,这样就避免了多线程并发操作和锁竞争,提升了 I/O 线程的处理和调度性能 - 设置并绑定服务端
Channel
作为NIO服务端,需要创建ServerSocketChannel
,Netty对原生的NIO类库进行了封装,对应实现了NioServiceSocketChannel
对于用户而言,不必关心服务端Channel 的底层实现细节和工作原理,只需要指定具体使用那种服务端Channel即可,因此,Netty 的ServerBootstrap
方法提供了channel 方法用于指定服务端Channel
类型,Netty通过工厂类,利用反射创建NioServerSocketChannel
对象由于服务端监听端口往往只需要在系统启动时才会调用,因此反射对性能影响并不大。 - 链路建立的时候创建并初始化
ChannelPipeline
,ChannelPipline 并不是NIO 服务端必须的,它本质就是一个负责处理网络事件的职责链,负责管理和执行ChannelHandler
网络事件以流的形式ChannelPiplien
中流转,由ChannelPipline
根据ChannelHandler
的执行策略调度ChannelHandler
的执行。典型的网络事件如下。- 链路注册
- 链路激活
- 链路断开
- 接收到请求消息
- 请求消息接收并处理完毕
- 发送应答消息
- 链路发生异常
- 发生用户自定义事件
- 初始化
ChannelPipline
完成后,添加并设置ChannelHandler
。ChannelHandler是Netty提供给用户定制和扩展的关键接口。利用ChannelHandler 用户可以完成大多数功能定制,例如消息编码、心跳、安全认证、TSL/SSL认证、流量控制和流量整形等。Netty同时也提供了大量的系统ChannelHandler
供用户使用,比较实用的系统ChannelHandler
例如- 系统编码框架 —— ByteToMessageCodec
- 通用基于长度的半包解码器 —— LengthFieldBasedFrameDecoder
- 码流日志打印 Handler —— LoggingHandler
- SSL 安全认证 Handler —— SslHandler
- 链路空闲检查 Handler —— IdleStateHandler
- 流量整形 Handler —— ChannelTrafficShapingHandler
- Base64 编解码 —— Base64Decoder 和 Base64Encoder
- 绑定并启动监听端口。在绑定监听端口之前,系统会做一系列的初始化和检测工作,完成之后,会启动监听端口,并将ServerSocketChannel 注册到Selector 上监听客户端链接。
- Selector 轮询。由Reactor 线程NioEventLoop 负责调度和执行Selector 轮询操作,选择准备就绪的Channel集合。
- 当轮询到准备就绪的Channel之后,就由 Reactor 线程 NioEventLoop 执行ChannelPipline 的相应方法,最终调度并执行 ChannelHandler。
- 执行 Netty 系统 CHannelHandler 和用户添加定制的 ChannelHandler 根据网络事件的类型,调度并执行 ChannelHandler。
并不是必须要创建两个不同的 EventLoopGroup ,也可以是一个共享的 EventLoopGroup A = new Nio EventLoopGroup(); EventLoopGroup B = new Nio EventLoopGroup();
NioEventLoopGroup 实际就是Reactor 线程池,负责调度和执行客户端接入、网络读写事件和处理、用户自定义任务和定时任务通过
ServerBootstrap
的group方法将两个EventLoopGroup 实例穿入
客户端流程
Netty 客户端的创建更加复杂,需要考虑线程模型、异步链接、客户端链接超时等因素。还需要对链接过程中的各种异常进行考虑。
Bootstrap 是 Socket 客户端创建工具类通过,
Bootstrap
可以方便的创建Netty客户端并发起异步TCP链接操作/
- 用户线程创建
Bootstrap
实例,通过API设置创建客户端相关参数,异步发起客户端链接 - 创建处理客户端链接、I/O读写的
Reactro
线程组 NioEventLoopGroup 。可以通过构造函数指定 I/O 线程个数,默认为CPU的两倍; - 通过
Bootstrap
的ChannelFactory和用户指定的Channel类型创建用于客户端链接的NioSocketChannel,它的功能类似于JDK NIO 类库提供的SocketChennal; - 创建默认的Channel Handler Pipline 用于调度和执行网络事件
- 异步发现TCP链接,判断链接是否成功。如果成功,则直接将NioSocketChannel注册到多路复用器上,监听读操作为,用于数据报读取和消息发送,如果没有立即链接成功,则注册链接监听位到多路复用,等待链接结果
- 注册对应的网络监听状态位到多路复用器
- 由多路复用器在I/O现场中轮询各Channel,处理链接结果
- 如果链接成功,设置Future结果,发送链接成功事件,触发ChannelPipline执行
- 由ChannelPipline 调度执行系统用户的ChannelHandler,执行业务逻辑
零散内容
Bootstrap 启动参数
参数 | 说明 |
---|---|
SO_TIMEOUT | 控制读取操作将阻塞多少毫秒。如果返回值为0,计时器就被禁止了,该线程将无限期阻塞。 |
SO_SNDBUF | 套接字实用的发送缓冲区大小 |
SO_RCVBUF | 套接字实用的接收缓冲区大小 |
SO_REUSEADDR | 用于决定如果网络上仍然有数据向旧的 ServerSocket 传输数据,是否运行新的 ServerSocket 绑定到与旧的ServerSocket 同样的端口上。 SO_REUSEADDR 选项的默认值与操作系统有关,在某些操作系统中,运行重用端口,而在某些操作系统中不允许重用端口 |
CONNECT_TIMEOUT_MILLIS | 客户端链接超时时间,由于NIO原生的客户端并不提供设置链接超时接口,因此,Netty 采用的是自定义链接超时定时器负责检测和超时控制 |
TCP_NODELAT | 激活或禁止 TCP_NODELAY 套接字选项,它决定是否实用Nagle算法,如果是时延敏型的应用,建议关闭Nagle 算法 |
TODO