Netty核心组件详解


通过前⾯的文章,我们对Netty的整体开发有了初步的了解,在Netty中有⼀些核⼼组件,我们必须对其要有深刻的理解,下⾯我们⼀⼀来了解下。
Netty快速入门
Netty快速入门RPC项目

1 Channel

Channel可以理解为是socket连接,在客户端与服务端连接的时候就会建⽴⼀个Channel,它负责基本的IO操作,⽐如:bind()、connect(),read(),write() 等。

Netty 的 Channel 接⼝所提供的 API,⼤⼤地降低了直接使⽤ Socket 类的复杂性。不同协议、不同的阻塞类型的连接都有不同的 Channel 类型与之对应,常⽤的 Channel 类型:

NioSocketChannel,NIO的客户端 TCP Socket 连接。
NioServerSocketChannel,NIO的服务器端 TCP Socket 连接。
NioDatagramChannel, UDP 连接。
NioSctpChannel,客户端 Sctp 连接。
NioSctpServerChannel,Sctp 服务器端连接,这些通道涵盖了 UDP 和 TCP ⽹络 IO 以及⽂件IO。

2 EventLoop、EventLoopGroup

有了 Channel 连接服务,连接之间可以消息流动。如果服务器发出的消息称作“出站”消息,服务器接受的消息称作“⼊站”消息。那么消息的“出站”/“⼊站”就会产⽣事件(Event)。

例如:连接已激活;数据读取;⽤户事件;异常事件;打开链接;关闭链接等等。
有了事件,就需要⼀个机制去监控和协调事件,这个机制(组件)就是EventLoop。

在 Netty 中每个 Channel 都会被分配到⼀个 EventLoop。⼀个 EventLoop 可以服务于多个 Channel。每个 EventLoop 会占⽤⼀个 Thread,同时这个 Thread 会处理 EventLoop 上⾯发⽣的所有 IO 操作和事件。
在这里插入图片描述
EventLoopGroup 是⽤来⽣成 EventLoop 的,在前⾯的例⼦中,第⼀⾏代码就是 newNioEventLoopGroup();

// 主线程,不处理任何业务逻辑,只是接收客户的连接请求
EventLoopGroup boss = new NioEventLoopGroup(1);
// ⼯作线程,线程数默认是:cpu*2
EventLoopGroup worker = new NioEventLoopGroup();

如果没有指定线程数⼤⼩,默认线程数为:cpu核数*2,源码如下:

static {
        DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
        "io.netty.eventLoopThreads", NettyRuntime.availableProcessors()
        * 2)); //可⽤cpu核数 * 2
        if (logger.isDebugEnabled()) {
        logger.debug("-Dio.netty.eventLoopThreads: {}",
        DEFAULT_EVENT_LOOP_THREADS);
        }
     }

上图关系为:
⼀个 EventLoopGroup 包含⼀个或者多个 EventLoop;
⼀个 EventLoop 在它的⽣命周期内只和⼀个 Thread 绑定;
所有由 EventLoop 处理的 I/O 事件都将在它专有的 Thread 上被处理;
⼀个 Channel 在它的⽣命周期内只注册于⼀个 EventLoop;
⼀个 EventLoop 可能会被分配给⼀个或多个 Channel。

3 ChannelHandler

ChannelHandler对使⽤者⽽⾔,可以说是最重要的组件了,因为对于数据的⼊站和出站的业务逻辑的编写都是在ChannelHandler中完成的。
在前⾯的例⼦中,MyChannelHandler就是实现了channelRead⽅法,获取到客户端传来的数据。

对于数据的出站和⼊站,有着不同的ChannelHandler类型与之对应:
ChannelInboundHandler ⼊站事件处理器
ChannelOutBoundHandler 出站事件处理器
接⼝继承关系如下:
在这里插入图片描述
ChannelHandlerAdapter提供了⼀些⽅法的默认实现,可减少⽤户对于ChannelHandler的编写。
ChannelInboundHandlerAdapter 与 SimpleChannelInboundHandler的区别:
在服务端编写ChannelHandler时继承的是ChannelInboundHandlerAdapter
在客户端编写ChannelHandler时继承的是SimpleChannelInboundHandler
两者的区别在于,前者不会释放消息数据的引⽤,⽽后者会释放消息数据的引⽤。
在这里插入图片描述

4 ChannelPipeline

在Channel的数据传递过程中,对应着有很多的业务逻辑需要处理,⽐如:编码解码处理、读写操作等,那么对于每种业务逻辑实现都需要有个ChannelHandler完成,也就意味着,⼀个Channel对应着多个ChannelHandler,多个ChannelHandler如何去管理它们,它们的执⾏顺序⼜该是怎么样的,这就需要ChannelPipeline进⾏管理了。

在这里插入图片描述

⼀个Channel包含了⼀个ChannelPipeline,⽽ChannelPipeline中维护了⼀个ChannelHandler的列表。

ChannelHandler与Channel和ChannelPipeline之间的映射关系,由ChannelHandlerContext进⾏维护。
它们关系如下:
在这里插入图片描述
ChannelHandler按照加⼊的顺序会组成⼀个双向链表,⼊站事件从链表的head往后传递到最后⼀个
ChannelHandler,出站事件从链表的tail向前传递,直到最后⼀个ChannelHandler,两种类型的
ChannelHandler相互不会影响。

5 Bootstrap

Bootstrap是引导的意思,它的作⽤是配置整个Netty程序,将各个组件都串起来,最后绑定端⼝、启动Netty服务。

Netty中提供了2种类型的引导类,⼀种⽤于客户端(Bootstrap),⽽另⼀种(ServerBootstrap)⽤于服务器。

在这里插入图片描述

它们的区别在于:
ServerBootstrap 将绑定到⼀个端⼝,因为服务器必须要监听连接,⽽ Bootstrap 则是由想要连接到远程节点的客户端应⽤程序所使⽤的。
引导⼀个客户端只需要⼀个EventLoopGroup,但是⼀个ServerBootstrap则需要两个。

因为服务器需要两组不同的 Channel第⼀组将只包含⼀个 ServerChannel,代表服务器⾃身的已绑定到某个本地端⼝的正在监听的套接字。

第⼆组将包含所有已创建的⽤来处理传⼊客户端连接。
在这里插入图片描述
与ServerChannel相关联的EventLoopGroup 将分配⼀个负责为传⼊连接请求创建 Channel 的
EventLoop。⼀旦连接被接受,第⼆个 EventLoopGroup 就会给它的 Channel 分配⼀个 EventLoop。

6 Future

Future提供了⼀种在操作完成时通知应⽤程序的⽅式。这个对象可以看作是⼀个异步操作的结果的占位符,它将在未来的某个时刻完成,并提供对其结果的访问。JDK 预置了 interface java.util.concurrent.Future,但是其所提供的实现,只允许⼿动检查对应的操作是否已经完成,或者⼀直阻塞直到它完成。这是⾮常繁琐的,所以 Netty 提供了它⾃⼰的实现——ChannelFuture,⽤于在执⾏异步操作的时候使⽤。

ChannelFuture提供了⼏种额外的⽅法,这些⽅法使得我们能够注册⼀个或者多个ChannelFutureListener实例。

监听器的回调⽅法operationComplete(),将会在对应的 操作完成时被调⽤ 。然后监听器可以判断该操作是成功地完成了还是出错了。
每个 Netty 的出站 I/O 操作都将返回⼀个 ChannelFuture,也就是说,它们都不会阻塞。 所以说,Netty完全是异步和事件驱动的。
在这里插入图片描述
上图是 serverBootstrap.bind(port) ⽅法底层的逻辑实现。

7 小结

在这里插入图片描述
通过以上图将Netty中的核⼼组件串起来。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵广陆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值