下文: 构建Netty应用
项目地址: https://gitee.com/bigzibo/pp-netty-rpc
netty初步学习
本文结合自己的一些思考和netty实战书写
简介与特性
分类 | Netty的特性 |
---|---|
设计 | 统一的API支持多种传输类型 阻塞的和非阻塞的简单而强大的线程模型 真正的无连接数据报套接字支持 链接逻辑组件以支持复用 |
易于使用 | 详实的Javadoc和大量的示例集不需要超过JDK 1.6+③的依赖。(一些可选的特性可能需要Java 1.7+和/或额外的依赖) |
性能 | 拥有比 Java 的核心 API 更高的吞吐量以及更低的延迟得益于池化和复用,拥有更低的资源消耗最少的内存复制 |
健壮性 | 不会因为慢速、快速或者超载的连接而导致 OutOfMemoryError消除在高速网络中 NIO 应用程序常见的不公平读/写比率 |
安全性 | 完整的 SSL/TLS 以及 StartTLS 支持可用于受限环境下,如 Applet 和 OSGI |
社区驱动 | 发布快速而且频繁 |
netty是异步和事件驱动的 《netty实战》中如是介绍
异步(也就是非同步)事件肯定大家都熟悉。考虑一下电子邮件:你可能会也可能不会收到你已经发出去的 电子邮件对应的回复,或者你也可能会在正在发送一封电子邮件的时候收到一个意外的消息。异 步事件也可以具有某种有序的关系。通常,你只有在已经问了一个问题之后才会得到一个和它对 应的答案,而在你等待它的同时你也可以做点别的事情。 在日常的生活中,异步自然而然地就发生了,所以你可能没有对它考虑过多少。但是让一个 计算机程序以相同的方式工作就会产生一些非常特殊的问题。本质上,一个既是异步的又是事件 驱动的系统会表现出一种特殊的、对我们来说极具价值的行为:它可以以任意的顺序响应在任意 的时间点产生的事件。 这种能力对于实现最高级别的可伸缩性至关重要,定义为:“一种系统、网络或者进程在 需要处理的工作不断增长时,可以通过某种可行的方式或者扩大它的处理能力来适应这种增长 的能力。
对于我们的通信来说, nio与bio的区别就是是否异步, 请求进入io之后, 线程可以继续运行,
例如继续发起请求, 而之前的请求得到回复后会有一个回调通知线程, 线程再安排时间去处理
而netty中的selector会很好的节约资源, 通过较少的线程就可以监听许多连接上的事件
将这些元素结合在一起,与使用阻塞 I/O 来处理大量事件相比,使用非阻塞 I/O 来处理更快 速、更经济。从网络编程的角度来看,这是构建我们理想系统的关键,而且你会看到,这也是 Netty 的设计底蕴的关键。
Netty的核心组件
-
Channel
Channel是nio的一个基本构造
它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执 行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作
可以将channel看做是传入或者输出数据的载体, 因此可以被打开或者关闭, 连接或者断开
-
回调
一个回调其实就是一个方法, 一个指向已经被提供给另外一个方法的方法
上面的介绍可能听起来有些繁杂, 通俗一点的解释就是: 一个方法的引用被另一个方法获得,
后者在进行到某一阶段的时候使用这个引用, 执行这个方法.
netty中连接建立后channelActive方法会被执行 -
Future
Future 提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操
作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。
netty实现的ChannelFuture可以注册监听器来监听事件是否完成
所以说netty是非阻塞的, 我们通过监听器来操作future的结果返回后的业务逻辑,
原先发起请求的线程在写入数据完毕后就可以去处理其他工作, 更加压榨了我们机器的性能ChannelFuture future = channel.connect(xxx); // 这里添加一个监听器, 监听future返回的结果 future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) { // 操作如果成功了, 就发一条信息 if (future.isSuccess()){ ByteBuf buffer = Unpooled.copiedBuffer( "Hello",Charset.defaultCharset()); ChannelFuture wf = future.channel() .writeAndFlush(buffer); .... } else { Throwable cause = future.cause(); cause.printStackTrace(); } } });
连接channel需要一定时间, 所以交给future处理
-
事件和ChannelHandler
每一个事件都会被对应的处理器去处理, 处理器可以处理读, 连接, 连接断开, 读异常等等事件
netty的channelHandler为处理器做了基本的抽象, 你可以认为每个 ChannelHandler 的实例都类似于一种为了响应特定事件而被执行的回调
-
总结
Netty的异步模型就是建立在Future和回调的概念上的
在Netty中会给每一个Channel分配一个EventLoop, 用以处理事件, 包括- 注册感兴趣的事件
- 将事件派发给ChannelHandler
- 安排进一步的动作
通过一个线程可以去监控多个Channel实现了资源的利用
基于NIO的Netty
新的还是非阻塞的
NIO 最开始是新的输入/输出(New Input/Output)的英文缩写,但是,该Java API 已经出现足够长的时间
了,不再是“新的”了,因此,如今大多数的用户认为NIO 代表非阻塞 I/O(Non-blocking I/O),而阻塞I/O(blocking
I/O)是旧的输入/输出(old input/output,OIO)。你也可能遇到它被称为普通I/O(plain I/O)的时候。
多个连接如果一一去监听处理, 那么就无法实现nio的非阻塞性, 所以nio设计了一个selector
class java.nio.channels.Selector 是Java 的非阻塞 I/O 实现的关键。它使用了事件通知 API以确定在一组非阻塞套接字中有哪些已经就绪能够进行 I/O 相关的操作。因为可以在任何的时间检查任意的读操作或者写操作的完成状态
这将意味着我们只需要一个线程作为selector就可以处理多个并发的连接, 当selector中没有需要执行的任务的时候, 线程就可以去做其他任务
后记
初步了解了netty之后, 可以尝试使用netty搭建一个简单的服务器与客户端进行通信
后续我会直接利用netty做一个简易的rpc框架