Netty,之前听过一句话,不会Netty,别说你是Java高级。这玩意到底是啥呢?
各种资料看了下,原来就是一款框架啊。为了网络编程而生。和java中的套接字有得一比。
既然是框架,设计思想很重要。
我们来了解下:
Netty
Netty是一款Java框架,用于快速开发高性能的网络应用,
它封装了网络编程的复杂性.
使用 apache maven作为它的管理工具
Netty是一款框架,设计原则: 每个小点都和它的技术性一样重要,穷奇精妙。
Java既有的网络编程的局限
java.net包只提供了一套使用本地系统套接字库提供的阻塞函数
也就是 创建网络编程需要安装如下的步骤进行:
监听某个端口,创建一个 ServerSocket
ServerSocket serverSocket = new ServerSocket(portNumber) ;
然后 使用 accept方法得到一个 客户端的套接字
Socket clientSocket = serverSocket.accept();
这样clientSocket就和 serverSocket进行通信了
使用 clientSocket的流处理可以进行数据的传输
BufferedReder bi = new BufferedReader(
new InpustStreamReader(clientSocket.getInpu·stStream())
);
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream());
使用流就可以进行处理了
传统的java的套接字的缺陷
我们可以看到这种代码同时只能处理一个连接,如果要管理多个客户端的时候,就要给每个客户端的
socket创建一个线程来处理.
这样问题转换为了多线程。
但是如果连接数目很高的时候,线程直接的管理以及创建,切换等管理遇到的问题就很尖锐了.
采用多线程进行处理的特点就是消耗内存
通过多个并发的线程来达到高并发的目的。
Netty的处理
netty使用一个 选择器来进行,使这个多线程的处理转变为单线程的处理
netty使用的是 nio 非阻塞io 的使用 non blocking i/o
这个思想是借鉴与 函数式编程的 例如 nodejs的并发实现,
采用 单线程但是 消耗cpu计算能力来得到的高并发
因此这种机制是 事件驱动型的
java.nio.channels.Selector
异步和事件驱动
nodejs使用 的异步,函数式编程思想,单线程的处理,消耗cpu计算达到 高并发处理
异步: 非阻塞,非阻塞网络调用使我们可以不必等待一个操作完成
nio的选择器使我们能够通过很少的线程便可以监视许多链接上的事件。
从这里引出了 Netty 的 特性 :
异步,模仿的nodejs的处理方式,因此是 事件驱动型的
事件,回调,channel 等等
异步的特性: 事情处理完了要想办法通知主程序
回调函数是一种通知方式。
Netty中的 Future也是一种通知的方式
Netty的核心组件
- channel
- 回调
- Future
- 事件和ChannelHandler
channel
channel是java nio 的一个基本构造
表示一个到实体的开放链接,
这个实体可以是:
- 硬件设备
- 文件
- 网路套接字
- 能够执行 io操作的组件
和其名字一样,表示一个 渠道,管道,和上面的实体链接之后,那么就是上面这些实体的数据的载体。
我们对实体的数据以及实体数据的传出都是用这个channel
回调--ChannelHandler
这个不陌生了,js的异步特性中的回调函数.
所以回调本身表示一个 方法 , 也就是该方法的引用提供给另外一个方法。
在c中可以认为是函数的指针,js中就是函数的句柄,java中函数是存在于对象上的,
因此可以使用包装该函数的接口对象
Netty内部使用 回调来处理事件响应。(监听器注册一个函数,当事件触发的时候就回调一个函数)
接口 ChannelHandler来处理的
该接口中有一个 channelActive方法,这个就是一个回调函数
这个类似于 awt编程中的 ActionLiistener的 actionPerformed函数一样。
可以类比: 当一个channel链接到一个实体的时候,那么同时注册这个channel对应的处理
channelHandler的接口函数,一旦有事件出现的时候,就会调用这个函数进行事件的处理
这个方法的签名是:
public void channelActive(ChannelHandlerContext ctx)
ChannelHandlerContext 就是我们获取当前channel的媒介
Future
Future提供了另外一种在操作完成时候通知应用程序的方式
这个对象可以看作是一个 异步操作结果的占位符。它将在未来某个时刻完成并提供对其结果的访问.
Future 接口
JDK 是提供了Future的
java.util.concurrent.Future 接口,但是它提供的实现是只能手动的检查对应的操作是否完成
ChannelFuture实现类
ChannelFuture , 用于在执行异步操作的时候使用
这个 ChannelFuture的实现是借鉴于 Action Listener的
ChannelFutureListener 监听器
ChannelFuture 提供了几种不同的方法可以注册一个或注册多个
ChannelFutureListener的实例,同样监听器有自己的回调方法的---operationComplete()
这个很类似于 actionPerformed方法.
public void operationComplete(ChannelFuture future)
可以想象 这个 ChannelFuture和我们的 awt中的 Button是很类似的
他们都可以注册监听器,监听器中封装了回调方法
每个netty的出站 I/O操作 都将返回一个 ChannelFuture 对象.
这样每个I/O操作都不阻塞.
如下的模式进行操作:
- 获取channel
- 使用channel异步连接远程节点,得到channelfuture
- 使用channelfuture注册监听 channelfuturelistener
- 实现listener的回调函数 operationComplete方法
Channel channel = ...
ChannelFuture future = channel.concet (new InetSocketAddress("192.168.0.1",25));
future.addListner(new ChannelFutureListener() {
operationComplete( ChannelFuture future) {
if(future.isSuccess()) {
} else {
Throwable cause = future.cause();
}
}
});
我们可以看到每一个 channelfuture都将会注册一个 channelfutureListener
ChannelFuture
也就是说可以识别到底是哪一个future的监听结果
事件和ChannelHandler
Netty是基于事件触发的,会通过各种各样的事件通知我们程序的状态
Netty是一个网络编程框架,事件是安装入站和出站数据流的相关性进行分类的
入站事件
连接已被激活或者连接失活
数据读取
用户事件
错误事件
出站事件
打开或关闭远程节点连接
将数据写入或冲刷套接字
每个事件都被分发给 用户实现的 ChannelHandler接口方法
综合
Netty的异步编程是基于 Future 和 回调函数的
而且是事件驱动的
但是每个事件分配给FutureHandler是更深层次的东西。
因为事件很多,因此Netty提供了很多重要的 FutureHandler
而且在内部,FutureHandler也使用了很多的事件和Future
ChannelFuture和回调是相互补充的机制。
ChannelFutureListener是一个精细的回调
No1 Future , 回调 , ChannelHandler
No2 选择器,事件 , EventLoop
选择器 就是来进行事件派发的操作,Netty将选择器给抽象出来了
而且 为每个 channel 分配一个 EventLoop,用于处理所有事件
EventLoop
EventLoop是一个线程驱动,这个和nodejs的循环事件一样
它将处理一个channel的所有I/o