在深入Netty 之前我们先从BIO 到 NIO的演变入手
ServerSocket serverSocket = new ServerSocket(54132);
Socket socket = serverSocket.accept();
//TODO
上述代码 是我们最开始接触网络编程中BIO代码。这段代码将只能同时处理一个连接,要管理多个并发客户端,需要为每个新的客户端socket建立一个新的线程。形成如下的格局:
但是会有如下问题: 1、在任何时候都可能有大量的线程处于休眠状态,只能等待输入或输出数据。简单来说就是,因为等待I/O而浪费了整个线程资源。
2、需要为每个线程的调用栈分配内存,其默认值的大小区间为64KB到1MB。
3、线程的上下文切换带来不小的开销。
针对BIO所出现的弊端,非阻塞设计的NIO也应运而生。下面是NIO设计;
selector 是java的非阻塞I/O实现的关键。他使用了事件通知API以确定在一组非阻塞套接字中有哪些已经就绪能够进行I/O相关操作,一个单一线程便可以处理多个并发链接。要知道在不是多核的电脑上执行的多线程效率并非必单线程阻塞占便宜,因为线程的切换也是需要一定的开销。
在高负载下可靠和高效的处理和调度I/O操作是一项繁琐而且容易出错的任务,因而高性能的网络编程专家 Netty 便登场了。
Netty 的特性总结
分类 | Netty 的特性 |
设计 | 统一的API,支持多种传输类型,阻塞和非阻塞的。 简单而强大的线程模型 真正的无连接数据报套接字支持 链接逻辑组件以支持复用 |
性能 | 拥有比java的核心API更高的吞吐量以及更低的延迟 得益于池化和复用,拥有更低的资源消耗 最少的内存复制 |
健壮性 | 不会因为慢速、快速或者超载而导致OutOfMemoryErro 消除在高速网络中NIO应用程序常见的不公平读/写比率 |
安全性 | 完整的SSL/TLS以及StartTLS支持 |
Netty 核心组件概述
更多细节内容将会在后续博文展开,这里只进行概述,方便理解后续的代码。
- Channel,表示一个连接,可以理解为每一个请求,就是一个Channel。
- ChannelHandler,核心处理业务就在这里,用于处理业务请求。
- 回调:一个回调其实就是一个方法,一个指向已经被提供给另一个方法的方法引用。这使得后者可以再适当的时候调用前者。可能不好理解,下面通过一段代码来具体说明。
//当一个新连接已经被建立时,channelActive方法将会被调用
public class ConnectHandle extends ChannelInboundHandlerAdapter {
@Override
public void channelActive (ChannelHandlerContext ctx) {
// TODO
}
}
- Future 提供了另一种在操作完成时通知应用程序的方式。这个对象可以看做是一个异步操作的结果占位符;他将在未来的某个时刻完成,并提供对其结果的访问。JDK所提供的Future只允许手动检查对应的操作是否已完成,或者一直阻塞直到它完成。因而Netty提供了自己的实现-channelFuture,用于在执行异步时使用。channelfuture允许我们注册一个或多个监听者,然后监听者的回调方法会在对应的操作完成后被调用。下面通过一个例子来具体说明。
Channel channel;
//异步链接远程节点
ChannelFuture future = channel.connect(new InetSocketAddress("localhost", 54132));
//注册一个监听者以便在操作完成时获得通知
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
//检查状态
if(future.isSuccess()) {
//TODO
}else {
//TODO
}
}
})
- ChannelHandlerContext,用于传输业务数据。
- ChannelPipeline,用于保存处理过程需要用到的ChannelHandler和ChannelHandlerContext。
- 最后