ChannelPipeline

来源:互联网 发布:freebsd和centos 编辑:程序博客网 时间:2024/06/06 03:34
转载自:http://blog.csdn.net/z69183787/article/details/52623501

       ChannelPipeline实际上应该叫做ChannelHandlerPipeline,可以把ChannelPipeline看成是一个ChandlerHandler的链表,当需要对Channel进行某种处理的时候,Pipeline负责依次调用每一个Handler进行处理。每个Channel都有一个属于自己的Pipeline,调用Channel#pipeline()方法可以获得Channel的Pipeline,调用Pipeline#channel()方法可以获得Pipeline的Channel。
       ChannelPipeline并不是直接管理ChannelHandler,而是通过ChannelHandlerContext来间接管理,这一点通过ChannelPipeline的默认实现DefaultChannelPipeline可以看出来。
/** * The default {@link ChannelPipeline} implementation.  It is usually created * by a {@link Channel} implementation when the {@link Channel} is created. */public class DefaultChannelPipeline implements ChannelPipeline {    …    final AbstractChannelHandlerContext head;    final AbstractChannelHandlerContext tail;    private final Channel channel;    …
       AbstractChannelHandlerContext的定义如下:
abstract class AbstractChannelHandlerContext extends DefaultAttributeMap        implements ChannelHandlerContext, ResourceLeakHint {    …    volatile AbstractChannelHandlerContext next;    volatile AbstractChannelHandlerContext prev;    private final boolean inbound;    private final boolean outbound;    private final DefaultChannelPipeline pipeline;    private final String name;    private final boolean ordered;    …
       Channel、ChannelPipeline、ChannelHandlerContext会形成如下关系:
     
       在ChinnelPipeline内部,ChannelHandlerContext组成了一个双向链表,ChinnelPipeline内部会使用了两个head和tail变量来标志头和尾。

       那么事件如何在Pipeline里传播呢?从Channel的抽象子类AbstractChannel开始,下面是AbstractChannel#write()方法的实现:
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {    ...    @Override    public ChannelFuture write(Object msg) {        return pipeline.write(msg);    }
       AbstractChannel直接调用了Pipeline的write()方法,再看DefaultChannelPipeline的write()方法实现:
    @Override    public final ChannelFuture write(Object msg) {        return tail.write(msg);    }
       因为write是个outbound事件,所以DefaultChannelPipeline直接找到tail指向的ChannelHandlerContext,调用其write()方法,接着看AbstractChannelHandlerContext的write()方法:
    @Override    public ChannelFuture write(Object msg) {        return write(msg, newPromise());    }
    @Override    public ChannelFuture write(final Object msg, final ChannelPromise promise) {        if (msg == null) {            throw new NullPointerException("msg");        }        try {            if (isNotValidPromise(promise, true)) {                ReferenceCountUtil.release(msg);                // cancelled                return promise;            }        } catch (RuntimeException e) {            ReferenceCountUtil.release(msg);            throw e;        }        write(msg, false, promise);        return promise;    }
    private void write(Object msg, boolean flush, ChannelPromise promise) {        AbstractChannelHandlerContext next = findContextOutbound();        final Object m = pipeline.touch(msg, next);        EventExecutor executor = next.executor();        if (executor.inEventLoop()) {            if (flush) {                next.invokeWriteAndFlush(m, promise);            } else {                next.invokeWrite(m, promise);            }        } else {            AbstractWriteTask task;            if (flush) {                task = WriteAndFlushTask.newInstance(next, m, promise);            }  else {                task = WriteTask.newInstance(next, m, promise);            }            safeExecute(executor, task, promise, m);        }    }
    private AbstractChannelHandlerContext findContextOutbound() {        AbstractChannelHandlerContext ctx = this;        do {            ctx = ctx.prev;        } while (!ctx.outbound);        return ctx;    }
       ChannelHandlerContext的write()方法沿着context链往前找,直至找到一个outbound类型的context为止,然后调用其invokeWrite()方法,最终调用ChannelOutboundHandler的write方法,即ChannelOutboundHandlerAdapter的write方法:
    @Override    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {        ctx.write(msg, promise);    }
       这里会调用context链中前一个outbound的ChannelHandlerContext的write,然后重复上述流程,这样write事件就沿着outbound链继续传播。

Netty中的inbound事件通常由I/O线程触发,例如TCP链路建立事件、链路关闭事件、读事件、异常通知事件等。触发Inbound事件的方法如下:
     1)ChannelHandlerCOntext.fireChannelRegistered():Channel注册事件;
     2)ChannelHandlerContext.fireChannelActive():TCP链路建立成功,Channel激活事件;
     3)ChannelHandlerContext.fireChannelRead(Object):读事件;
     4)ChannelHandlerContext.fireChannelReadComplete():读操作完成通知事件;
     5)ChannelHandlerContext.fireExceptionCautght(Throwable):异常通知事件;
     6)ChannelHandlerContext.fireUserEventTriggered(Object):用户自定义事件;
     7)ChannelHandlerContext.fireChannelWritabilityChanged():Channel的可写状态变化通知事件;
     8)ChannelHandlerContext.fireChannelInactive():TCP连接关闭,链路不可用通知事件。

Outbound事件通常是用户主动发起的网络I/O操作,例如用户发起的连接操作、绑定操作、消息发送等操作。触发outbound事件的方法如下:
     1)ChannelHandlerContext.bind(SocketAddress, ChannelPromise):绑定本地地址事件;
     2)ChannelHandlerContext.connect(SocketAddress, SocketAddress, ChannelPromise):连接服务端事件;
     3)ChannelHandlerContext.write(Object, ChannelPromise):发送事件;
     4)ChannelHandlerContext.flush():刷新事件;
     5)ChannelHandlerContext.read():读事件;
     6)ChannelHandlerContext.disconnect(ChannelPromise):断开连接事件;
     7)ChannelHandlerContext.close(ChannelPromise):关闭当前Channel事件;



补充:
       ChannelPipeline是一个大的接口,是一个Facade门面模式的实例。它主要包括三部分的接口,
          1. 链表的接口,包括各种遍历,修改链表的操作;
          2. inbound事件的接口,以fireXXXX开头的方法;
          3. outbound事件的接口, 不带fire的方法,比如read, write,bind, connect等。
       inbound,outbound事件是Netty抽象的事件概念,从底层IO事件到用户事件的方向是inbound事件,从用户事件到底层IO事件的方向是outbound事件

       DefaultChannelPipeline是ChannelPipeline接口的具体实现,它处理实际的事件分发。它采用了两个单链表head, tail 来处理inbound,outbound事件。
       单链表的节点是ChannelHandlerContext,它通过next, prev两个指针指向前后的节点。head链表的第一个节点是HeadHandler, tail节点的第一个节点是TailHandler。HeadHandler里面封装了Unsafe接口, 来进行实际的IO读写。inbound事件从底层IO开始,outbound事件到底层IO结束,所以inbound事件链的起点从HeadHandler开始,outbound事件链的终点在HeadHandler结束。



连接在pipeline的整个生命周期是:
Server端:
       1、ServerSocketChannel: fireChannelRegistered(注册到EventLoop) -> bind(绑定端口)-> fireChannelActive(激活) -> 【 read(注册OP_ACCEPT到SelectorKey) -> fireChannelRead(接收到客户端连接,此时会将客户端连接注册到workerGroup) -> fireChannelReadComplete(读取客户端连接完成) -> 接收下一个连接】 -> 直到最终关闭触发fireChannelUnregistered(从EventLoop中取消注册);
       2、SocketChannel: ServerSocketChannel接收到客户端请求后,将其注册到workerGroup -> fireChannelRegistered(注册) -> fireChannelActive (激活) ->【 read(注册OP_READ到SelectorKey) -> fireChannelRead(读取到数据) -> (业务数据处理) -> write(写数据到buffer) -> flush(数据最终发送)/ writeAndFlush(前两个操作的组合) -> fireChannelReadComplete(读取过程结束)】 -> fireChannelInactive(连接关闭) -> fireChannelUnregistered(从EventLoop中取消注册);

Client端:
       SocketChannel: fireChannelRegistered(注册到EventLoop) -> connect(连接server) -> fireChannelActive(连接成功) -> 【 read(注册OP_READ) ->  write(写数据到buffer) -> flush(数据最终发送) / writeAndFlush(前两个操作的组合) -> fireChannelRead(读取到server传回的数据) -> (业务数据处理) -> fireChannelReadComplete(读取完成)】-> fireChannelInactive(接收关闭连接的请求)-> close(关闭连接) ->  fireChannelUnregistered(从EventLoop中取消注册);
       上面是一个简化的监听、连接、处理、关闭流程,实际的流程会更加复杂。


原创粉丝点击