Channel;- 回调;
Future;- 事件和
ChannelHandler。
Channel
Channel是Java NIO的一个基本构造。
它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作
目前,可以把Channel 看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者被关闭,连接或者断开连接。
回调
一个回调 其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。
Netty在内部使用了回调来处理事件;当一个回调被触发时,相关的事件可以被一个interface-ChannelHandler 的实现处理。
下面的例子展示了:当一个新的连接已经被建立时,ChannelHandler 的channelActive() 回调方法将会被调用,并将打印出一条信息:
public class ConnectHandler extends ChannelInboundHandlerAdapter {@Overridepublic 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() {@Overridepublic void operationComplete(ChannelFuture future) {//检查操作的状态if (future.isSuccess()){//如果操作是成功的,则创建一个ByteBuf以持有数据ByteBuf buffer = Unpooled.copiedBuffer("Hello",Charset.defaultCharset());//将数据异步地发送到远程节点。//返回一个ChannelFutureChannelFuture wf = future.channel().writeAndFlush(buffer);....} else {//如果发生错误,则访问描述原因的ThrowableThrowable 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 中需要进行同步的任何顾虑。
