1、Netty中的Channel

1.1、Channel简介

为了支持多种通信协议,Netty实现了一系列的Channel组件

Reactor模式和通道紧密相关,反应器的查询和分发IO事件都来自于Channel组件

类名 解释
NioSocketChannel 异步非阻塞的客户端TCP Socket连接。
NioServerSocketChannel 异步非阻塞的服务器端TCP Socket连接。
NioDatagramChannel 异步非阻塞的UDP连接。
NioSctpChannel 异步的客户端(Stream Control Transmission Protocol,流控制传输协议)连接。
NioSctpServerChannel 异步的Sctp服务器端连接。
OioSocketChannel 同步阻塞的客户端TCP Socket连接。
OioServerSocketChannel 同步阻塞的服务器端TCP Socket连接。
OioDatagramChannel 同步阻塞的UDP连接。
OioSctpChannel 同步的Sctp服务器端连接。
OioSctpServerChanner 同步的客户端TCP Socket连接。

1.2、父子通道

在Netty中每个NioSocketChannel通道所封装的都是java NIO通道,再往下就是操作系统底层的socket文件描述符。理论上来说操作系统底层的socket文件描述符分为两种:

  • 连接监听类型 :连接监听类型的socket描述符在服务端,负责接收客户端的套接字连接。在服务端一个“连接监听类型”的socket描述符可以接受成千上万个传输类型的socket文件描述符
  • 数据传输类型:数据传输类型的socket描述符负责传输数据。同一条TCP的socket传输链路在服务器和客户端分别会有一个与之对应的数据传输类型的socket文件描述符。

在Netty中,将具有接收关系的监听通道和传输通道叫做父子关系。其中负责服务器连接和接收的监听通道(如NioServerSocketChannel)也叫父通道,对应于每个接收到的传输类通道(如NioSocketChannel)也叫做子通道。

2、EventLoop和EventLoopGoup

2.1、EventLoop

在Netty中一个EventLoop相当于一个子反应器,一个EventLoop拥有一个事件轮询线程,同时拥有一个选择器。

继承关系

EventLoop.png

2.2、EventLoopGoup

Netty中的Reactor模式是多线程版本的,使用EventLoopGroup将多个EventLoop线程放在一起,可以实现多线程版本的Reactor模式实现。
EventloopGroup是一个多线程版本的反应器,而单个的EventLoop对应一个子反应器。

  1. //io任务,普通任务,定时任务
  2. EventLoopGroup nioEventLoopGroup = new NioEventLoopGroup(8);
  3. //普通任务,定时任务
  4. EventLoopGroup eventExecutors = new DefaultEventLoop();
  5. //获取下一个事件循环对象
  6. IntStream.range(0,10).forEach(e -> System.out.println(nioEventLoopGroup.next()));
  7. //执行普通任务
  8. nioEventLoopGroup.next().submit(()->{
  9. try {
  10. Thread.sleep(1000);
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. log.info("ok");
  15. });
  16. //执行定时任务
  17. nioEventLoopGroup.next().scheduleAtFixedRate(() -> {
  18. System.out.println("ok");
  19. },0,1, TimeUnit.SECONDS);

构造函数说明:
EventLoopGroup构造函数中有个指定内部线程数的参数,按照传入的线程数量构造EventLoop子反应器,进行多线程的IO事件查询和分发。如果没有传入线程数量或者传入线程数量为0,则取配置io.netty.eventLoopThreads ,如果没有配置则取CPU处理器数量的两倍
private static final int DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

Netty中EventLoopGroup使用

在服务端一般有两个独立的反应器,一个负责新连接的监听和接收,另一个负责IO事件轮询和分发,并且两个反应器相互隔离。对应到Netty服务器程序中,应该设置两个EventGroup,一个负责新连接的监听和接收,另外一个负责传输事件的轮询和分发

3、Netty中的Handler

EventLoop反应器内部有个线程负责IO事件的轮询,然后进行对应事件的分发,事件分发的目标就是Netty的Handler

Netty的Handler分为两类,ChannelInboundHandler 入站处理器,ChannelOutboundHandler 出站处理器
image.png

4、Netty中的Pipeline

Netty中Reactor模式实现各组件的关系:
(1)反应器(EventLoop)和通道(Channel)间是一对多关系,一个反应器可轮询多个通道的IO事件
(2)通道(Channel)和处理器(Handler)为多对多关系,一个通道的事件可以被多个Handler实例处理,一个Handler实例也可以绑定到很多通道,处理多个通道的IO事件

问题:通道和Handler处理器实例间的绑定关系Netty是如何组织的?

Netty设计了一个特殊组件,叫做ChannelPipeLine(通道流水线)。它像一条管道,将绑定到一个通道的多个Handler处理器实例串联在一起。

ChannelPipeLine的默认设计为双向链表。 每个Netty通道拥有一个名为pipeline的ChannelPipeline类型成员属性

特点:

  • Netty流水线为双向的,入站处理器的执行次序是从前往后,出站处理器的执行次序是从后往前
  • 入站的IO操作只能从入站处理器类型的Handler流过,出站的IO操作只能从出站处理器类型的Handler流过