Netty 框架学习 —— 初识 Netty
Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端
Java 网络编程
早期的 Java API 只支持由本地系统套接字库提供的所谓的阻塞函数,下面的代码展示了一个使用传统 Java API 的服务器代码的普通示例
// 创建一个 ServerSocket 用以监听指定端口上的连接请求
ServerSocket serverSocket = new ServerSocket(5000);
// 对 accept 方法的调用将被阻塞,直到一个连接建立
Socket clientSocket = serverSocket.accept();
// 这些流对象都派生于该套接字的流对象
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
String request, response;
// 客户端发送了 "Done" 则退出循环
while ((request = in.readLine()) != null) {
if ("Done".equals(request)) {
break;
}
// 请求被传递给服务器的处理方法
response = processRequest(request);
// 服务器的响应被发送给客户端
out.println(response);
}
这段代码只能同时处理一个连接,要管理多个客户端,就要为每个新的客户端 Socket 创建一个新的 Thread,让我们来考虑一下这种方案的影响:
- 在任何时候都会有大量线程处于休眠状态,造成资源浪费
- 需要为每个线程的调用栈都分配内存
- 线程的上下文切换会带来开销
这种并发方案对于中小数量的客户端还算理想,但不能很好地支持更大的并发,幸运的是,还有另一种解决方案
Java NIO
NIO(Non-blocking I/O,也称 New I/O),是一种同步非阻塞的 I/O 模型,也是 I/O 多路复用的基础。传统的 IO 流是阻塞的,这意味着,当一个线程调用读或写操作时,线程将被阻塞,直至数据被完全读取或写入。NIO 的非阻塞模式,使一个线程进行读或写操作时,如果目前无数据可用时,就不做操作,而不是保持线程阻塞,所以直至数据就绪以前,线程可以继续做其他事情
class java.nio.channels.Selector 是 Java 非阻塞 IO 实现的关键。它使用事件通知 API 以确定在一组非阻塞套接字中有哪些已经就绪并能进行 IO 相关操作。因为可以在任何时间点任意检查读操作或写操作的完成情况,所以单一线程可以处理多个并发的连接
与阻塞 IO 模型相比,这种模型提供了更好的资源管理:
- 使用较少的线程便可以处理许多连接,减少内存管理和上下文切换所带来的开销
- 当没有 IO 操作需要处理时,线程也可以用户其他任务
尽管 Java NIO 如此高效,但要做到正确和安全并不容易,在高负载下可靠和高效地处理和调度 IO 操作是一项烦琐且容易出错的任务,所幸,有 Netty 能帮助我们解决问题
Netty
Netty 是一个广泛使用的 Java 网络编程框架,它隐藏了 Java 高级 API 背后的复杂性,提供一个易于使用的 API 的客户端/服务器框架。在这里我们将要讨论 Netty 的主要构件:
1. Channel
Channel 是 Java NIO 的一个基本构造,可以把 Channel 简单看作是传入(入站)或传出(出站)数据的载体。因此,它可以被打开或关闭,连接或断开连接
2. 回调
一个回调其实就是一个方法,Netty 使用回调来处理事件,当一个回调被触发时,相关的事件可以被 ChannelHandler 的实现处理。下面的代码展示了这样一个例子:当一个新的连接已经建立,ChannelHandler 的 channelActive() 的回调方法将会被调用,并打印出一条信息
public class ConnectHandler extends ChannelInboundHandlerAdapter {
@override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client " + ctx.channel().remoteAddress() + " connected");
}
}
3. Future
Future 提供了另一种在操作完成时通知应用程序的方式,它将在未来的某个时刻完成,并提供对其结果的访问。虽然 Java 提供了 Future 的一种实现,但需要手动检查对应操作是否已经完成,或一直阻塞直到它完成,十分烦琐。Netty 提供了自己的实现 ChannelFuture,用于执行异步操作的时候使用
ChannelFuture 提供了几种额外的方法,这些方法使得我们能够注册一个或多个 ChannelFutureListener 实例。监听器的回调方法 operationComplete() 将会在对应操作完成时被调用。每个 Netty 的 IO 操作都会返回一个 ChannelFuture,它们都不会被阻塞,可以同时做其他工作,更加有效的利用资源
Channel channel = ...;
// 异步地连接到远程结点
ChannelFuture future = channel.connect(new InetSocketAddress("192.168.0.1", 25));
// 注册一个 ChannelFutureListener
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
// 如果操作成功
if(future.isSuccess()) {
...
} else {
// 发生异常
...
}
}
});
4. 事件和 ChannelHandler
Netty 使用不同的事件来触发合适的动作,事件是按照与入站或出站数据流的相关性进行分类的,可能由入站数据或相关状态更改而触发的事件包括:
- 连接已被激活或失效
- 数据读取
- 用户事件
- 错误事件
出站事件是未来将会触发的某个动作的操作结果,包括:
- 打开或关闭到远程结点的连接
- 将数据写到或冲刷到套接字
每个事件都可分发给 ChannelHandler 类中的某个用户实现的方法,下图展示了一个事件如何被一个 ChannelHandler 链处理
Netty 提供了大量预定义的 ChannelHandler 实现,供开发者使用
5. 总结
Netty 的异步编程模型是建立在 Future 和回调的概念之上的,将事件派发到 ChannelHandler 拦截并高速地转换入站数据和出站数据,开发者只需要提供回调或者利用返回的 Future 即可。Netty 通过触发事件将 Selector 从应用程序中抽象出来,消除了本需手写的派发代码。在内部,将会为每个 Channel 分配一个 EventLoop,用于处理所有事件,包括:
- 注册感兴趣的时间
- 将事件派发给 ChannelHandler
- 安排进一步的动作
EventLoop 本身只有一个线程驱动,处理了一个 Channel 的所有 IO 事件,这个简单而强大的设计消除了可能在 ChannelHandler 实现中需要进行同步的任何顾虑,因此我们只需专注于提供正确的逻辑即可
Netty 框架学习 —— 初识 Netty的更多相关文章
- Netty 框架学习 —— 基于 Netty 的 HTTP/HTTPS 应用程序
通过 SSL/TLS 保护应用程序 SSL 和 TLS 安全协议层叠在其他协议之上,用以实现数据安全.为了支持 SSL/TLS,Java 提供了 javax.net.ssl 包,它的 SSLConte ...
- Netty 框架学习 —— 传输
概述 流经网络的数据总是具有相同的类型:字节,这些字节如何传输主要取决于我们所说的网络传输.用户并不关心传输的细节,只在乎字节是否被可靠地发送和接收 如果使用 Java 网络编程,你会发现,某些时候当 ...
- Netty 框架学习 —— 引导
概述 前面我们学习了 ChannelPipeline.ChannelHandler 和 EventLoop 之后,接下来的问题是:如何将它们组织起来,成为一个可实际运行的应用程序呢?答案是使用引导(B ...
- Netty 框架学习 —— 编解码器框架
编解码器 每个网络应用程序都必须定义如何解析在两个节点之间来回传输的原始字节,以及如何将其和目标应用程序的数据格式做相互转换.这种转换逻辑由编解码器处理,编解码器由编码器和解码器组成,它们每种都可以将 ...
- Netty 框架学习 —— 第一个 Netty 应用
概述 在本文,我们将编写一个基于 Netty 实现的客户端和服务端应用程序,相信通过学习该示例,一定能更全面的理解 Netty API 该图展示的是多个客户端同时连接到一台服务器.客户端建立一个连接后 ...
- Netty 框架学习 —— EventLoop 和线程模型
EventLoop 接口 Netty 是基于 Java NIO 的,因此 Channel 也有其生命周期,处理一个连接在其生命周期内发生的事件是所有网络框架的基本功能.通常来说,我们使用一个线程来处理 ...
- Netty 框架学习 —— 预置的 ChannelHandler 和编解码器
Netty 为许多提供了许多预置的编解码器和处理器,几乎可以开箱即用,减少了在烦琐事务上话费的时间和精力 空闲的连接和超时 检测空闲连接以及超时对于释放资源来说至关重要,Netty 特地为它提供了几个 ...
- Netty 框架学习 —— Netty 组件与设计
Channel.EventLoop 和 ChannelFuture 这一节将对 Channel.EventLoop 和 ChannelFuture 类进行讨论,它们组合在一起,可以被认为是 Netty ...
- Netty 框架学习 —— ByteBuf
概述 网络数据的基本单位总是字节,Java NIO 提供了 ByteBuffer 作为它的字节容器,但这个类的使用过于复杂.Netty 的 ByteBuf 具有卓越的功能性和灵活性,可以作为 Byte ...
- Netty 框架学习 —— ChannelHandler 与 ChannelPipeline
ChannelHandler 1. Channel 生命周期 Channel 的生命周期状态如下: 状态 描述 ChannelUnregistered Channel 已经被创建,但还未注册到 Eve ...
随机推荐
- 【慢SQL性能优化】 一条SQL的生命周期
一. 一条简单SQL在MySQL执行过程 一张简单的图说明下,MySQL架构有哪些组件和组建间关系,接下来给大家用SQL语句分析 例如如下SQL语句 SELECT department_id FROM ...
- WebSocket魔法师:打造实时应用的无限可能
1.背景 在开发一些前端页面的时候,总是能接收到这样的需求:如何保持页面并实现自动更新数据呢?以往的常规做法,是前端使用定时轮询后端接口,获取响应后重新渲染前端页面,这种做法虽然能达到类似的效果,但是 ...
- goto关键词
1.前言 goto,一个蒟蒻一用就废,大佬一用就吊炸天的神奇关键字. 今天,我要来盘它!!! 2.goto只能在函数内实现跳转,不能跨函数跳转 因为标号label是局部有效的. #include &l ...
- Python学习成绩>=90分的同学用A表示,60-89分之间的用B表示,60分以下的用C表示。
def SlowSnail(score): name = input('请输入姓名:') if score >= 90: grade = 'A' elif score >= 60: gra ...
- 基于.net6.0 Fast.ORM 已全面支持AOT编译 所有Api均测试通过
Fast Framework 作者 Mr-zhong 代码改变世界.... 一.前言 Fast Framework 基于NET6.0 封装的轻量级 ORM 框架 支持多种数据库 SqlServer O ...
- C#/.NET/.NET Core推荐学习书籍(已分类)
前言 古人云:"书中自有黄金屋,书中自有颜如玉",说明了书籍的重要性.作为程序员,我们需要不断学习以提升自己的核心竞争力.以下是一些优秀的C#/.NET/.NET Core相关学习 ...
- 如何用BI制作图表组合?
BI(Business Intelligence)是一种通过收集.分析和可视化数据来帮助企业做出决策的技术和工具.在BI中,制作图表组合是一种常见的方式,可以将不同的图表类型组合在一起,以更全面地呈现 ...
- chatgpt接口开发笔记3: 语音识别接口
chatgpt接口开发笔记3: 语音识别接口 1.文本转语音 1.了解接口参数 接口地址: POST https://api.openai.com/v1/audio/speech 下面是接口文档描述内 ...
- 【scikit-learn基础】--『数据加载』之样本生成器
除了内置的数据集,scikit-learn还提供了随机样本的生成器.通过这些生成器函数,可以生成具有特定特性和分布的随机数据集,以帮助进行机器学习算法的研究.测试和比较. 目前,scikit-lear ...
- [ABC238G] Cubic?
Problem Statement Given a sequence $A$ of $N$ numbers, answer the following $Q$ questions. In the $i ...