Channel
;- 回调;
Future
;- 事件和
ChannelHandler
。
Channel
Channel是Java NIO的一个基本构造。
它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作
目前,可以把Channel
看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者被关闭,连接或者断开连接。
回调
一个回调 其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。
Netty在内部使用了回调来处理事件;当一个回调被触发时,相关的事件可以被一个interface-ChannelHandler
的实现处理。
下面的例子展示了:当一个新的连接已经被建立时,ChannelHandler
的channelActive()
回调方法将会被调用,并将打印出一条信息:
public class ConnectHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx)
throws Exception {
//当一个新的连接已经被建立时,channelActive(ChannelHandlerContext)将会被调用
System.out.println(
"Client " + ctx.channel().remoteAddress() + " connected");
}
}
Future
Future
提供了另一种在操作完成时通知应用程序的方式。
JDK预置了interface java.util.concurrent.Future
,但是其所提供的实现,只允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成。这是非常繁琐的,所以Netty提供了它自己的实现——ChannelFuture
,用于在执行异步操作的时候使用。
下面展示了一个ChannelFuture
作为一个I/O操作的一部分返回的例子。connect()
方法将会直接返回,而不会阻塞,该调用将会在后台完成。
Channel channel = ...;
// Does not block
//异步地连接到远程节点
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()){
//如果操作是成功的,则创建一个ByteBuf以持有数据
ByteBuf buffer = Unpooled.copiedBuffer(
"Hello",Charset.defaultCharset());
//将数据异步地发送到远程节点。
//返回一个ChannelFuture
ChannelFuture wf = future.channel()
.writeAndFlush(buffer);
....
} else {
//如果发生错误,则访问描述原因的Throwable
Throwable cause = future.cause();
cause.printStackTrace();
}
}
});
ChannelFuture
提供了几种额外的方法,这些方法使得我们能够注册一个或者多个ChannelFutureListener
实例。监听器的回调方法operationComplete()
,将会在对应的操作完成时被调用 。
回调和Future
是相互补充的机制;它们相互结合,构成了Netty本身的关键构件块之一。
事件和ChannelHandler
Netty使用不同的事件来通知我们状态的改变或者是操作的状态。
入站事件:
- 记录日志;
- 数据转换;
- 流控制;
- 应用程序逻辑。
出站事件:
- 连接已被激活或者连接失活;
- 数据读取;
- 用户事件;
- 错误事件。
每个事件都可以被分发给ChannelHandler
类中的某个用户实现的方法。(事件被分发给channelHandler).
Netty提供了大量预定义的可以开箱即用的ChannelHandler
实现,包括用于各种协议(如HTTP和SSL/TLS)的ChannelHandler
。在内部,ChannelHandler
自己也使用了事件和Future 。
选择器、事件和EventLoop
Netty通过触发事件将Selector
从应用程序中抽象出来,消除了所有本来将需要手动编写的派发代码。在内部,将会为每个Channel
分配一个EventLoop
,用以处理所有事件,(评:为每个channel分配一个EventLoop)包括:
- 注册感兴趣的事件;
- 将事件派发给
ChannelHandler
; - 安排进一步的动作。
EventLoop
本身只有一个线程驱动,其处理了一个Channel
的所有I/O事件,并且在该EventLoop
的整个生命周期内都不会改变。这个简单而强大的设计消除了你可能有的在你的ChannelHandler
中需要进行同步的任何顾虑。