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 NIONIO(Non-blocking I/O,也称 New I/O),是一种同步非阻塞的 I/O 模型,也是 I/O 多路复用的基础 。传统的 IO 流是阻塞的,这意味着,当一个线程调用读或写操作时,线程将被阻塞,直至数据被完全读取或写入 。NIO 的非阻塞模式,使一个线程进行读或写操作时,如果目前无数据可用时,就不做操作,而不是保持线程阻塞,所以直至数据就绪以前,线程可以继续做其他事情
class java.nio.channels.Selector 是 Java 非阻塞 IO 实现的关键 。它使用事件通知 API 以确定在一组非阻塞套接字中有哪些已经就绪并能进行 IO 相关操作 。因为可以在任何时间点任意检查读操作或写操作的完成情况,所以单一线程可以处理多个并发的连接

文章插图
与阻塞 IO 模型相比,这种模型提供了更好的资源管理:
- 使用较少的线程便可以处理许多连接,减少内存管理和上下文切换所带来的开销
- 当没有 IO 操作需要处理时,线程也可以用户其他任务
NettyNetty 是一个广泛使用的 Java 网络编程框架,它隐藏了 Java 高级 API 背后的复杂性,提供一个易于使用的 API 的客户端/服务器框架 。在这里我们将要讨论 Netty 的主要构件:
1. ChannelChannel 是 Java NIO 的一个基本构造,可以把 Channel 简单看作是传入(入站)或传出(出站)数据的载体 。因此,它可以被打开或关闭,连接或断开连接
2. 回调一个回调其实就是一个方法,Netty 使用回调来处理事件,当一个回调被触发时,相关的事件可以被 ChannelHandler 的实现处理 。下面的代码展示了这样一个例子:当一个新的连接已经建立,ChannelHandler 的 channelActive() 的回调方法将会被调用,并打印出一条信息
public class ConnectHandler extends ChannelInboundHandlerAdapter {@overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("Client " + ctx.channel().remoteAddress() + " connected");}}3. FutureFuture 提供了另一种在操作完成时通知应用程序的方式,它将在未来的某个时刻完成,并提供对其结果的访问 。虽然 Java 提供了 Future 的一种实现,但需要手动检查对应操作是否已经完成,或一直阻塞直到它完成,十分烦琐 。Netty 提供了自己的实现 ChannelFuture,用于执行异步操作的时候使用ChannelFuture 提供了几种额外的方法,这些方法使得我们能够注册一个或多个 ChannelFutureListener 实例 。监听器的回调方法 operationComplete() 将会在对应操作完成时被调用 。每个 Netty 的 IO 操作都会返回一个 ChannelFuture,它们都不会被阻塞,可以同时做其他工作,更加有效的利用资源
Channel channel = ...;// 异步地连接到远程结点ChannelFuture future = channel.connect(new InetSocketAddress("192.168.0.1", 25));// 注册一个 ChannelFutureListenerfuture.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future) {// 如果操作成功if(future.isSuccess()) {...} else {// 发生异常...}}});4. 事件和 ChannelHandlerNetty 使用不同的事件来触发合适的动作,事件是按照与入站或出站数据流的相关性进行分类的,可能由入站数据或相关状态更改而触发的事件包括:- 连接已被激活或失效
- 数据读取
- 用户事件
- 错误事件
- 打开或关闭到远程结点的连接
- 将数据写到或冲刷到套接字

文章插图
Netty 提供了大量预定义的 ChannelHandler 实现,供开发者使用
5. 总结Netty 的异步编程模型是建立在 Future 和回调的概念之上的,将事件派发到 ChannelHandler 拦截并高速地转换入站数据和出站数据,开发者只需要提供回调或者利用返回的 Future 即可 。Netty 通过触发事件将 Selector 从应用程序中抽象出来,消除了本需手写的派发代码 。在内部,将会为每个 Channel 分配一个 EventLoop,用于处理所有事件,包括:
- 注册感兴趣的时间
- 将事件派发给 ChannelHandler
- 安排进一步的动作
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
