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));// 注册一个 ChannelFutureListenerfuture.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 实现中需要进行同步的任何顾虑,因此我们只需专注于提供正确的逻辑即可
原文转载:http://www.shaoqun.com/a/719750.html
赛兔:https://www.ikjzd.com/w/2375
知无不言:https://www.ikjzd.com/w/1308
Netty是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端Java网络编程早期的JavaAPI只支持由本地系统套接字库提供的所谓的阻塞函数,下面的代码展示了一个使用传统JavaAPI的服务器代码的普通示例//创建一个ServerSocket用以监听指定端口上的连接请求ServerSocketserverSocket=newServerSocket(50
woot:https://www.ikjzd.com/w/604
识货:https://www.ikjzd.com/w/1745
特许金融分析师:https://www.ikjzd.com/w/1396
Wish:明年起,英国增值税法规发生重要变更!:https://www.ikjzd.com/home/137321
秘书短信埋怨我老公床上粗鲁:http://lady.shaoqun.com/m/a/271827.html
每周精选:亚马逊红人计划来袭!卖家更改主图宣战跟卖!:https://www.ikjzd.com/home/5752
没有评论:
发表评论