ChannelPipeline
来源:互联网 发布:freebsd和centos 编辑:程序博客网 时间:2024/06/06 03:34
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中取消注册);
上面是一个简化的监听、连接、处理、关闭流程,实际的流程会更加复杂。
- ChannelPipeline
- Netty4 -- ChannelPipeline
- Netty:ChannelPipeline
- Netty4 ChannelPipeLine分析
- java netty之ChannelPipeline
- Netty的ChannelPipeline
- Floodlight 中 ChannelPipeline 结构图
- Netty3 源码分析 - ChannelPipeline
- 03 netty channelPipeline
- Netty4学习笔记-- ChannelPipeline
- 6 ChannelHandler and ChannelPipeline
- netty-channel-channelPipeline
- Netty教程-ChannelPipeline
- ChannelHandler和ChannelPipeline
- Netty源码分析:ChannelPipeline
- netty源码分析之ChannelPipeline
- netty源码分析之ChannelPipeline
- Netty 之 ChannelHandler,ChannelHandlerContext,ChannelPipeline
- poj1753之DFS
- 【2013年第四届蓝桥杯C/C++程序设计本科B组决赛 连续奇数和(结果填空) 】
- C
- 二叉树
- 通讯录1.0(可实现插入输出)
- ChannelPipeline
- 计算几何资料(不定时更新)
- win7远程桌面连接Ubuntu 14.04
- 总结(一)
- java多种方式实现1G文件复制
- 最好 FFmpeg 给视频 添加水印 添加标注
- 寄语
- 找出数组中每个数的右边第一个比它大的数
- 大数据架构和模式(一)大数据分类和架构简介