文章摘要(AI生成)
Netty是一个基于Java的异步事件驱动的网络应用框架,它通过对NIO进行封装,提供了更方便、高效的网络编程方式。
在传统的BIO(Blocking I/O)中,客户端与服务端之间都是单线程操作,导致效率低下。而在NIO(Non-blocking I/O)中,通过轮询和异步连接的方式,可以同时处理多个连接,提高并发性能。
Netty对NIO进行了封装,提供了更高级别的抽象和功能,使开发者能够更方便地进行网络编程。它提供了事件驱动的模型,通过事件的触发和处理,实现了异步、非阻塞的网络通信。
通过Netty,开发者不需要自己处理底层的轮询和异步连接,而是可以专注于业务逻辑的实现。Netty提供了许多内置的组件和工具,例如线程池、编解码器、协议支持等,使网络编程更加简单、高效。
总之,Netty通过对NIO的封装,提供了更方便、高效的网络编程方式,使开发者能够轻松地构建高性能的网络应用。
Netty如何对NIO进行封装?
温习BIO和NIO~
首先结合BIO和NIO,我们先看下网络编程中,客户端和服务端分别要做那几件事情:
顺序 | 事件 | 相应操作 |
---|---|---|
1 | 服务端初始化 | 绑定端口 |
2 | 服务端初始化 | 监听端口连接 |
3 | 客户端初始化 | 连接服务端 |
4 | 服务端工作 | 接收连接请求 |
5 | 服务端工作 | 创建连接通道 |
6 | 客户端工作 | 发送请求 |
7 | 服务端工作 | 接收请求 |
8 | 服务端工作 | 返回结果 |
9 | 客户端工作 | 处理结果 |
在BIO中,客户端与服务端之间都是单线程操作。上述过程对应线程为:
顺序 | 事件 | 相应操作 | 线程 |
---|---|---|---|
1 | 服务端初始化 | 绑定端口 | 服务端主线程 |
2 | 服务端初始化 | 监听端口连接 | 服务端主线程 |
3 | 客户端初始化 | 连接服务端 | 客户端主线程 |
4 | 服务端工作 | 接收连接请求 | 服务端主线程 |
5 | 服务端工作 | 创建连接通道 | 服务端主线程 |
6 | 客户端工作 | 发送请求 | 客户端主线程 |
7 | 服务端工作 | 接收请求 | 服务端连接线程 |
8 | 服务端工作 | 返回结果 | 服务端连接线程 |
9 | 客户端工作 | 处理结果 | 客户端主线程 |
其中服务端的主线程和连接线程需要我们自己做异步化才能区分开,归集下,可以得到下图所示处理流程:
图中,当有两个客户端连接服务端时,我们必须创建两个连接线程(一个连接线程顺序处理肯定会阻塞)来处理客户端对应的数据请求。而且客户端如果和服务端有多个连接时,那么客户端就会因为连接阻塞而影响后续操作。
而在BIO中,通过服务端轮询,客户端异步连接的方式,我们的线程分配又变为如下:
顺序 | 事件 | 相应操作 | 线程 |
---|---|---|---|
1 | 服务端初始化 | 绑定端口 | 服务端主线程 |
2 | 服务端初始化 | 监听端口连接 | 服务端主线程 |
3 | 客户端初始化 | 连接服务端 | 客户端主线程 |
4 | 服务端工作 | 接收连接请求 | 服务端主线程 |
5 | 服务端工作 | 创建连接通道 | 服务端主线程 |
6 | 客户端工作 | 发送请求 | 客户端主线程 |
7 | 服务端工作 | 接收请求 | 服务端轮询线程 |
8 | 服务端工作 | 返回结果 | 服务端轮询线程 |
9 | 客户端工作 | 处理结果 | 客户端主线程 |
归集上述流程,我们可以得到以下示意图:
通过NIO,我们解决了BIO中的两个缺陷:通过轮询的方式,我们虽然维护了多个连接,但不需要创建多个线程来保证并发性,通过一个轮询线程即可实现数据及时读取;通过异步建立连接的方式,客户端不会因为当前连接阻塞而影响后续操作。
Netty为我们做了什么?
我们自己基于NIO进行网络编程时,发现NIO的一个特点在于他只给了我们一个轮询通道和异步连接的功能,但是轮询和异步连接如何被发挥到极致完全看个人能力。这样就大大影响了实际应用里网络编程NIO的落地,很多人都会因为写不出好的网络编程代码而在现实的沟壑面前望洋兴叹。
那么Netty其实本质上就是对NIO的一层线程池封装,其实我们在自己做NIO编程时候已经发现,服务端和客户端的很多职责都可以划分给不同的线程池。
还是网络交互流程,我们可以将其划分到不同的线程池:
通过上述流程拆分,我们的线程池有如下几个:
线程池 | 事件 | 相应操作 |
---|---|---|
客户端-主线程组 | 客户端初始化 | 连接服务端 |
客户端-主线程组 | 客户端工作 | 发送请求 |
客户端-主线程组 | 客户端工作 | 处理结果 |
客户端-解析线程组 | 客户端工作 | 数据解码与编码 |
客户端-主线程组 | 服务端初始化 | 绑定端口 |
服务端-主线程组 | 服务端初始化 | 监听端口连接 |
服务端-主线程组 | 服务端工作 | 接收连接请求 |
服务端-主线程组 | 服务端工作 | 创建连接通道 |
服务端-轮询线程组 | 服务端工作 | 接收请求 |
服务端-轮询线程组 | 服务端工作 | 返回结果 |
服务端-轮询线程组 | 服务端工作 | 数据解码与编码 |
套用我们在NIO中介绍的例子,6条流水线有两个人时,我们通过一个人巡视,一个人分拣的方式完成了快递分拣工作。但是后续我们资金充裕后,需要向流水线增派人手,这时候自己设计的NIO编码拓展性就很难保证了:
而netty则是帮我们做了分组的思想,将不同的职责分给不同的线程池处理,这样我们的流水线就很好做到增加和减少人手了:
评论区