netty io.netty.channel介绍2

Interface ChannelHandlerContext

    上下文对象使得当前channelhandler能够与其所属的channelpipeline以及其余handler进行交互,能够通知所属channelpipeline中的下一个handler,也可动态修改其所属的channelpipeline,具体功能以下:html

    通知。经过调用channelhandlercontext提供的方法能够调用同一个channelpipeline中的相邻的下一个channelhandler,详情能够参照channelpipeline来了解事件使如何流动的。java

    修改pipeline  经过调用context的pipeline()方法能够获得当前handler所属的channelpipeline。能够在程序运行时动态增长、删除、替换channelpipeline中的handler。数据库

    保持供后面使用 你能够将context对象存储在handler中,共后面使用。好比在handler提供的方法以外触发一个事件,甚至在不一样的线程中均可以。实例代码以下:api

 public class MyHandler extends ChannelHandlerAdapter {     
     private ChannelHandlerContext ctx;//成员变量

     public void beforeAdd(ChannelHandlerContext ctx) {         
         this.ctx = ctx;//此处保持该ctx
     }

     public void login(String username, password) {//在自定义方法中触发事件
         ctx.write(new LoginMessage(username, password));
     }
     ...
 }

    存储状态信息 AttributeMap.attr(AttributeKey)方法容许你存储和访问与handler和context相关的状态信息。promise

    一个handler能够有多个context  因为同一个handler实例能够被添加到多个pipeline中,这也就意味着一个handler能够有一个或多个context对象,所以同一个handler实例若是被添加到一个或多个pipeline一次或者屡次,当其handle方法被调用的时候,传进来的参数context是不一样的。一个handler被添加到pipeline多少次,他就有多少各context对象,不是见到同一个pipeline仍是不一样的pipeline,示例代码以下:安全

 @Sharable
 public class FactorialHandler extends ChannelHandlerAdapter {

   private final AttributeKey<Integer> counter = AttributeKey.valueOf("counter");

   // This handler will receive a sequence of increasing integers starting
   // from 1.   @Override
   public void channelRead(ChannelHandlerContext ctx, Object msg) {     
     Attribute<Integer> attr = ctx.getAttr(counter);
     Integer a = ctx.getAttr(counter).get();

     if (a == null) {
       a = 1;
     }

     attr.set(a * (Integer) msg);
   }
 }

 // Different context objects are given to "f1", "f2", "f3", and "f4" even if
 // they refer to the same handler instance.  Because the FactorialHandler
 // stores its state in a context object (using an AttributeKey), the factorial is
 // calculated correctly 4 times once the two pipelines (p1 and p2) are active.
 FactorialHandler fh = new FactorialHandler(); 
 ChannelPipeline p1 = Channels.pipeline();
 p1.addLast("f1", fh);//一个context
 p1.addLast("f2", fh); //二个context
 ChannelPipeline p2 = Channels.pipeline();
 p2.addLast("f3", fh);//三个context
 p2.addLast("f4", fh);//四个context


Interface ChannelHandlerInvoker

    此接口调用ChannelHandler的事件处理方法,若是此接口的默认实现类不知足要求,用户能够指定一个ChannelHandlerInvoker实现一个自定义线程模型,注意这个接口的方法不是给用户调用的。async

Interface ChannelId

    表示一个channel全局惟一的标识符。标识符是根据下列资源产生的:MAC地址,当前进程ID,System.currentTimeMillis(),System.nanoTime(),一个随机的32-bit Integer和一个顺序增加的32-bit整数。标识符的全局惟一性有赖于MAC地址和进程ID,系统会在类加载的时候自动检测获取,若是这两个获取失败,系统会记录警告信息,同时将使用随机数代替做为标识符,另外,你能够经过系统属性人工指定这两个参数:io.netty.machineId 48bit或者64bit十六进制表示的整数,能够经过冒号后者连字符分割,io.netty.processId 0到65535之间的一个整数。
ide

Interface ChannelPipeline

    channelpipeline由一系列channelhandler组成,用来处理channel的inbound events 和 outbound operations。channelpipeline实现了拦截过滤器模式(Intercepting Filter pattern)的一种高级形式。以使用户可以彻底控制一个时间(event)怎样被处理,以及channelpipeline中的channelhandler之间如何交互。oop

    pipeline的建立  每个channel都一个本身的pipeline,channel建立的时候pipeline自动建立ui

    事件(event)如何在pipeline中流动 下图展现了一个IO事件被channelpipeline中的channelhandler处理的典型方式,一个IO事件被当前handler处理以后,将被转发到当前handler在channelpipeline中的紧邻的下一个handler处理。若是有必要的话,channelhandler自己也能够触发任意的IO事件。为了触发或者转发IO事件,channelhandler须要调用channelhandlercontext提供的事件传播方法,例如ChannelHandlerContext.fireChannelRead(Object)ChannelHandlerContext.write(Object).

                                                 I/O Request
                                            via Channel or                                        ChannelHandlerContext
                                                      |
  +---------------------------------------------------+---------------+
  |                           ChannelPipeline         |               |
  |                                                  \|/              |
  |    +----------------------------------------------+----------+    |
  |    |                   ChannelHandler  N                     |    |
  |    +----------+-----------------------------------+----------+    |
  |              /|\                                  |               |
  |               |                                  \|/              |
  |    +----------+-----------------------------------+----------+    |
  |    |                   ChannelHandler N-1                    |    |
  |    +----------+-----------------------------------+----------+    |
  |              /|\                                  .               |
  |               .                                   .               |
  | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
  |          [method call]                      [method call]         |
  |               .                                   .               |
  |               .                                  \|/              |
  |    +----------+-----------------------------------+----------+    |
  |    |                   ChannelHandler  2                     |    |
  |    +----------+-----------------------------------+----------+    |
  |              /|\                                  |               |
  |               |                                  \|/              |
  |    +----------+-----------------------------------+----------+    |
  |    |                   ChannelHandler  1                     |    |
  |    +----------+-----------------------------------+----------+    |
  |              /|\                                  |               |
  +---------------+-----------------------------------+---------------+
                  |                                  \|/
  +---------------+-----------------------------------+---------------+
  |               |                                   |               |
  |       [ Socket.read() ]                    [ Socket.write() ]     |
  |                                                                   |
  |  Netty Internal I/O Threads (Transport Implementation)            |
  +-------------------------------------------------------------------+

    如上图左边所示,一个inbound事件自底向上的被channelhandler处理,一个inbound事件一般是由IO线程触发(图底部),以便在channel状态发生变化(例如新建连接或者关闭链接)或者从远端读取数据的时候通知channelhandler。若是inbound事件超过了图中最顶端的channelhandler,该事件会被丢弃,并被记录,取决于日志级别。

    如上图右边所示,一个outbound事件自顶向下的被channelhandler处理,一个outbound事件一般是由用户的代码调用IO操做触发,例如写请求或者尝试进行连接。若是一个outbound事件超过了最底端的channelhandler,改事件会被与channel关联的IO线程处理,IO线程一般状况下执行实际的输出操做,好比SocketChannel.write(ByteBuffer).

    转发事件给下一个handler 就像上面解释的那样,channelhandler经过调用channelhandlercontext的事件传播方法将事件转发给下一个channelhandler,具体方式以下:


    下面的代码展现了事件传播的经常使用作法:

 public class MyInboundHandler extends ChannelHandlerAdapter {     
     @Override
     public void channelActive(ChannelHandlerContext ctx) {
         System.out.println("Connected!");
         ctx.fireChannelActive();//传播事件
     }
 }

 public clas MyOutboundHandler extends ChannelHandlerAdapter {    
     @Override
     public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
         System.out.println("Closing ..");
         ctx.close(promise);//传播事件
     }
 }

    构建pipeline 用户在pipeline中应该有一个或者多个channelhandler来接收IO事件(例如 read)或者请求IO操做(例如write  close)。例如,一个典型的server在每个channelpipeline中一般有以下channelhandler,可是具体细节可能不同,这取决于你的协议和业务逻辑的特性和复杂度:

  1. Protocol Decoder - translates binary data (e.g. ByteBuf) into a Java object.解码,将二进制数据转换成java对象

  2. Protocol Encoder - translates a Java object into binary data. 编码,讲java对象转换成二进制数据

  3. Business Logic Handler - performs the actual business logic (e.g. database access).业务逻辑处理(例如数据库存储)

    组装pipeline的示例代码以下:

 static final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
 ... 
 ChannelPipeline pipeline = ch.pipeline();

 pipeline.addLast("decoder", new MyProtocolDecoder());
 pipeline.addLast("encoder", new MyProtocolEncoder());

 // Tell the pipeline to run MyBusinessLogicHandler's event handler methods
 // in a different thread than an I/O thread so that the I/O thread is not blocked by
 // a time-consuming task.
 // If your business logic is fully asynchronous or finished very quickly, you don't
 // need to specify a group.若是业务逻辑是一个耗时任务或者会阻塞,请不要放在IO线程执行。
 pipeline.addLast(group, "handler", new MyBusinessLogicHandler());


    线程安全 channelpipeline中的channelhandler能够在任什么时候候添加删除,由于channelpipeline是线程安全的。例如你能够在发送敏感信息的时候添加一个加密的handler,在敏感信息发送以后删除这个handler。

Interface ChannelProgressiveFuture

    此接口表示一个特殊的channelfuture对象,用来展现FileRegion transfer 的进度

Interface ChannelProgressiveFutureListener

    An EventListener listener which will be called once the sending task associated with future is being transferred.

Interface ChannelProgressivePromise

    Special ChannelPromise which will be notified once the associated bytes is transferring.

Interface ChannelPromise

    Special ChannelFuture which is writable.

Interface EventLoop

    一旦channel注册以后,该接口处理全部关于该channel的IO操做,一个EventLoop一般状况下处理一个或多个channel,可是这取决于内部实现细节

Interface EventLoopGroup

    他容许注册channel,并在后面eventloop中处理channel

Interface FileRegion

    表示经过channel发送的一个文件区块,能够支持zero-copy file transfer.

Interface MessageSizeEstimator

    此接口负责计消息的大小,也就是消息在内存中占多大空间。

Interface RecvByteBufAllocator

    负责建立一个接收缓冲区,其大小适中,可以存储inbound data 又不浪费空间

Interface ServerChannel

    负责接接入的连接请求,并建立一个子channel来接收连接,具体实现能够参照ServerSocketChannel

相关文章
相关标签/搜索