• Channel
  • 回调;
  • Future
  • 事件和ChannelHandler

Channel

Channel是Java NIO的一个基本构造。

它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作

目前,可以把Channel 看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者被关闭,连接或者断开连接。

回调

一个回调 其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。

Netty在内部使用了回调来处理事件;当一个回调被触发时,相关的事件可以被一个interface-ChannelHandler 的实现处理。

下面的例子展示了:当一个新的连接已经被建立时,ChannelHandlerchannelActive() 回调方法将会被调用,并将打印出一条信息:

  1. public class ConnectHandler extends ChannelInboundHandlerAdapter {
  2. @Override
  3. public void channelActive(ChannelHandlerContext ctx)
  4. throws Exception {
  5. //当一个新的连接已经被建立时,channelActive(ChannelHandlerContext)将会被调用
  6. System.out.println(
  7. "Client " + ctx.channel().remoteAddress() + " connected");
  8. }
  9. }

Future

Future 提供了另一种在操作完成时通知应用程序的方式。

JDK预置了interface java.util.concurrent.Future ,但是其所提供的实现,只允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成。这是非常繁琐的,所以Netty提供了它自己的实现——ChannelFuture ,用于在执行异步操作的时候使用。

下面展示了一个ChannelFuture 作为一个I/O操作的一部分返回的例子。connect() 方法将会直接返回,而不会阻塞,该调用将会在后台完成

  1. Channel channel = ...;
  2. // Does not block
  3. //异步地连接到远程节点
  4. ChannelFuture future = channel.connect(
  5. new InetSocketAddress("192.168.0.1", 25));
  6. //注册一个ChannelFutureListener,以便在操作完成时获得通知
  7. future.addListener(new ChannelFutureListener() {
  8. @Override
  9. public void operationComplete(ChannelFuture future) {
  10. //检查操作的状态
  11. if (future.isSuccess()){
  12. //如果操作是成功的,则创建一个ByteBuf以持有数据
  13. ByteBuf buffer = Unpooled.copiedBuffer(
  14. "Hello",Charset.defaultCharset());
  15. //将数据异步地发送到远程节点。
  16. //返回一个ChannelFuture
  17. ChannelFuture wf = future.channel()
  18. .writeAndFlush(buffer);
  19. ....
  20. } else {
  21. //如果发生错误,则访问描述原因的Throwable
  22. Throwable cause = future.cause(); 
  23. cause.printStackTrace();
  24. }
  25. }
  26. });

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 中需要进行同步的任何顾虑。