- 简单说下 Netty 中的重要组件?NIO中Channel的作用?
一、NIO 中三大核心组件
- Buffer(缓冲区)。在NIO厍中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
- Channel(通道)。NIO 通过Channel(通道) 进行读写。通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。
- Selector(选择器)。NIO的选择器用于使用单个线程管理多个通道。只有在通道里真正有读写事件发生时(事件驱动),才会交给线程读写(Selector会一直询问每个通道有没有读写事件,这个过程是同步的),因此,它只需要较少的线程来处理这些通道。不必为每一个连接都创建一个线程,也不必去维护多个线程。避免了多个线程之间的上下文切换,导致资源的浪费。(只有网络IO才会使用选择器,文件IO是不需要使用的)
二、Netty 中核心组件
1.Channel
可以理解为是socket连接,在客户端与服务端连接的时候就会建⽴⼀个Channel,它负责基本的IO操作,⽐如:bind()、connect(),read(),write() 等。
2.EventLoop、EventLoopGroup
有了 Channel 连接服务,连接之间可以消息流动。如果服务器发出的消息称作“出站”消息,服务器接受的消息称作“⼊站”消息。那么消息的“出站/⼊站”就会产⽣事件(Event)。例如:连接已激活;数据读取;⽤户事件;异常事件;打开链接;关闭链接等等。
有了事件,就需要⼀个机制(EventLoop)去监控和协调事件。
- 在 Netty 中每个 Channel 都会被分配到⼀个 EventLoop。
- ⼀个 EventLoop 可以服务于多个 Channel。
- 每个 EventLoop 会占⽤⼀个 Thread,同时这个 Thread 会处理 EventLoop 上⾯发⽣的所有 IO 操作和事件。
EventLoop主要是配合 Channel,处理Channel的生命周期中所发生的事件。
EventLoopGroup 是⽤来⽣成和管理 EventLoop 的。
- ⼀个 EventLoopGroup 包含⼀个或者多个 EventLoop。
进阶:
一个 NioEventLoop 维护了一个 Selector (使用的是 Java 原生的 Selector )。
一个 NioEventLoop 相当于一个线程。
3.ChannelHandler
对于数据的⼊站和出站的业务逻辑的编写都是在ChannelHandler中完成的。
ChannelInboundHandler ⼊站事件处理器
ChannelOutBoundHandler 出站事件处理器
ChannelHandlerAdapter提供了⼀些⽅法的默认实现,可减少⽤户对于ChannelHandler的编写。
ChannelInboundHandlerAdapter 与 SimpleChannelInboundHandler的区别:
- 在服务端编写ChannelHandler时继承的是ChannelInboundHandlerAdapter
- 在客户端编写ChannelHandler时继承的是SimpleChannelInboundHandler
两者的区别在于,前者不会释放消息数据的引⽤,⽽后者会释放消息数据的引⽤。
4.ChannelPipeline
⼀个Channel对应着多个ChannelHandler,多个ChannelHandler如何去管理它们,它们的执⾏顺序⼜该是怎么样的,这就需要ChannelPipeline进⾏管理了。
- ⼀个Channel包含了⼀个ChannelPipeline。
- ⽽ChannelPipeline中维护了⼀个ChannelHandlerContext 的双向链表。
- 一个 ChannelHandlerContext 中包含一个 ChannelHandler。
5.Bootstrap
将 Netty 各个组件都串起来,最后绑定端⼝、启动Netty服务。
客户端(Bootstrap) 与 服务器(ServerBootstrap) 的区别:
- ServerBootstrap 将绑定到⼀个端⼝,因为服务器必须要监听连接,⽽ Bootstrap 则是由想要连接到远程节点的客户端应⽤程序所使⽤的。
- 引导⼀个客户端只需要⼀个EventLoopGroup,但是⼀个ServerBootstrap则需要两个。原因如下:
- 因为服务器需要两组不同的 Channel。第⼀组将只包含⼀个 ServerChannel,代表服务器⾃身的已绑定到某个本地端⼝的正在监听的Socket。第⼆组将包含所有已创建的⽤来处理传⼊客户端连接。
- 与ServerChannel相关联的EventLoopGroup 将分配⼀个负责为传⼊连接请求创建 Channel 的 EventLoop。⼀旦连接被接受,第⼆个 EventLoopGroup 就会给它的 Channel 分配⼀个 EventLoop。
6.ChannelFuture
这个对象可以看作是⼀个异步操作的结果的占位符,它将在未来的某个时刻完成,并提供对其结果的访问。
每个 Netty 的出站 I/O 操作都将返回⼀个 ChannelFuture,也就是说,它们都不会阻塞。
Netty 框架中所有的 I/O 操作都为异步的,因此我们需要 ChannelFuture 的 addListener()注册一个 ChannelFutureListener 监听事件,当操作执行成功或者失败时,监听就会自动触发返回结果。