# Netty源码解析
# ServerBootstrap与Bootstrap
- 它们都是继承于AbstractBootstrap,分别负责服务端与客户端;
- ServerBootstrap,服务端用于接收客户端的连接并为接收连接的用户创建Channel通道
- BootStrap,客户端不接收连接,并且是在父通道完成系列操作。
# ServerBootstrap
ServerBootstrap负责初始化netty服务器,并且开始监听端口的socket请求。
# NioEventLoopGroup
EventLoop如同它的名字,它是一个无限循环(Loop),在循环中不断处理接收到的事件(Event)
Netty线程模型的基石是建立在EventLoop上的,从设计上来看,EventLoop采用了一种协同设计,它建立在两个基本的API之上:Concurrent和Channel,也就是并发和网络。并发是因为它采用了线程池来管理大量的任务,并且这些任务可以并发的执行。其继承了EventExecutor接口,而EventExecutor就是一个事件的执行器。另外为了与Channel的事件进行交互,EventLoop继承了EventLoopGroup接口。一个详细的EventLoop类继承层次结构如下:
**一个Netty服务端启动时,通常会有两个NioEventLoopGroup:**一个是监听线程组,主要是监听客户端请求,另一个是工作线程组,主要是处理与客户端的数据通讯。
NioEventLoopGroup bossGroup = new NioEventLoopGroup();//处理连接工作
NioEventLoopGroup workerGroup = new NioEventLoopGroup();//数据处理
2
Netty客户端只有一个NioEventLoopGroup,就是用来处理与服务端通信的线程组。
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
NioEventLoopGroup可以理解为一个线程池,内部维护了一组线程,每个线程负责处理多个Channel上的事件,而一个Channel只对应于一个线程,这样可以回避多线程下的数据同步问题
- 对于Netty的使用,都会使用bossGroup和workerGroup的方式,而常说的bossGroup和workerGroup其实是NioEventLoopGroup的实例。
- 在Netty中,EventLoopGroup和NioEventLoopGroup其实就是一个线程池。
# ServerBootstrap的childHandler()与handler()的区别
ServerBootstrap的childHandler()与handler()添加的handlers是针对不同的EventLoopGroup起作用:
通过handler添加的handlers是对bossGroup线程组起作用
通过childHandler添加的handlers是对workerGroup线程组起作用
# Bootstrap的handler()
客户端Bootstrap只有handler()方法,因为客户端只需要一个事件线程组
# Channel 数据传输流
Channel,表示一个连接,可以理解为每一个请求,就是一个Channel。
ChannelHandler,核心处理业务就在这里,用于处理业务请求。
ChannelHandlerContext,用于传输业务数据。
ChannelPipeline,用于保存处理过程需要用到的ChannelHandler和ChannelHandlerContext。
Netty的Channel在JDK NIO的Channel基础上做了一层封装,提供了更多的功能。
Netty的中的Channel实现类主要有:
NioServerSocketChannel
(用于服务端非阻塞地接收TCP连接)
NioSocketChannel
(用于维持非阻塞的TCP连接)
NioDatagramChannel
(用于非阻塞地处理UDP连接)
OioServerSocketChannel
(用于服务端阻塞地接收TCP连接)
OioSocketChannel
(用于阻塞地接收TCP连接)
OioDatagramChannel
(用于阻塞地处理UDP连接):
# ByteBuf 存储字节的容器
维护了一个字节数组
维护了两个指针,一个是读指针,一个是写指针
1)duplicate方法:复制当前对象,复制后的对象与前对象共享缓冲区,且维护自己的独立索引
2)copy方法:复制一份全新的对象,内容和缓冲区都不是共享的
3)slice方法:获取调用者的子缓冲区,且与原缓冲区共享缓冲区
# Codec 编码/解码器
HttpRequestDecoder和HttpResponseEncoder
通过Netty发送和接收一个消息的时候,就会发生一次数据转换,入站消息会被解码,也就是从字节转换为原本的形式,如果是出站消息,就会从一种形式变成字节,这个就是编码,编解码的根本原因就是因为网络数据就是一系列的字节
# write
从性能角度考虑,为了防止频繁地唤醒Selector进行消息发送,Netty的write方法只是把待发送的消息放到发送缓冲数组,再通过调用flush方法,将发送缓冲区中的消息全部写到SoceketChannel中
# sync和syncUninterruptibly
sync():等待Future直到其完成,如果这个Future失败,则抛出失败原因;
syncUninterruptibly():不会被中断的sync();