`

【转】ChannelPipeline

 
阅读更多

【转】http://blog.csdn.net/zxhoo/article/details/17264263

Netty4

Netty是一个和MINA类似的Java NIO框架,目前的最新版本是4.0.13,这两个框架的主要作者好像都是同一个韩国人

 

Channel

Channel是Netty最核心的接口,一个Channel就是一个联络Socket的通道,通过Channel,你可以对Socket进行各种操作。

 

ChannelHandler

用Netty编写网络程序的时候,你很少直接操纵Channel,而是通过ChannelHandler来间接操纵Channel。

 

ChannelPipeline

ChannelPipeline实际上应该叫做ChannelHandlerPipeline,可以把ChannelPipeline看成是一个ChandlerHandler的链表,当需要对Channel进行某种处理的时候,Pipeline负责依次调用每一个Handler进行处理。每个Channel都有一个属于自己的Pipeline,调用Channel#pipeline()方法可以获得Channel的Pipeline,调用Pipeline#channel()方法可以获得Pipeline的Channel。

ChannelPipeline的方法有很多,其中一部分是用来管理ChannelHandler的,如下面这些:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. ChannelPipeline addFirst(String name, ChannelHandler handler);  
  2. ChannelPipeline addLast(String name, ChannelHandler handler);  
  3. ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);  
  4. ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);  
  5. ChannelPipeline remove(ChannelHandler handler);  
  6. ChannelHandler remove(String name);  
  7. ChannelHandler removeFirst();  
  8. ChannelHandler removeLast();  
  9. ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);  
  10. ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);  
  11. ChannelHandler first();  
  12. ChannelHandler last();  
  13. ChannelHandler get(String name);  

根据上面的方法,能够大概想象的到Pipeline按照什么样的方式组织Handler。

 

ChannelHandlerContext

ChannelPipeline并不是直接管理ChannelHandler,而是通过ChannelHandlerContext来间接管理,这一点通过ChannelPipeline的默认实现DefaultChannelPipeline可以看出来。

调用ChannelHandlerContext#channel()方法可以得到和Context绑定的Channel,调用ChannelHandlerContext#handler()方法可以得到和Context绑定的Handler。

 

ChannelPipeline和ChannelHandlerContext默认实现

DefaultChannelHandlerContext和DefaultChannelPipeline是ChannelHandlerContext和ChannelPipeline的默认实现,下面是它们的部分代码:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {  
  2.   
  3.     volatile DefaultChannelHandlerContext next;  
  4.     volatile DefaultChannelHandlerContext prev;  
  5.   
  6.     private final boolean inbound;  
  7.     private final boolean outbound;  
  8.     private final AbstractChannel channel;  
  9.     private final DefaultChannelPipeline pipeline;  
  10.     private final String name;  
  11.     private final ChannelHandler handler;  
  12.     private boolean removed;  
  13.   
  14.     // ...  
  15. }  
[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. final class DefaultChannelPipeline implements ChannelPipeline {  
  2.     // ...  
  3.   
  4.     final DefaultChannelHandlerContext head;  
  5.     final DefaultChannelHandlerContext tail;  
  6.   
  7.     // ...  
  8. }  


从上面的代码可以看出,在DefaultPipeline内部,DefaultChannelHandlerContext组成了一个双向链表:

 

再来看看DefaultChannelPipeline的构造函数:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. public DefaultChannelPipeline(AbstractChannel channel) {  
  2.     if (channel == null) {  
  3.         throw new NullPointerException("channel");  
  4.     }  
  5.     this.channel = channel;  
  6.   
  7.     TailHandler tailHandler = new TailHandler();  
  8.     tail = new DefaultChannelHandlerContext(thisnull, generateName(tailHandler), tailHandler);  
  9.   
  10.     HeadHandler headHandler = new HeadHandler(channel.unsafe());  
  11.     head = new DefaultChannelHandlerContext(thisnull, generateName(headHandler), headHandler);  
  12.   
  13.     head.next = tail;  
  14.     tail.prev = head;  
  15. }  


可以看到,DefaultChinnelPipeline内部使用了两个特殊的Handler来表示Handler链的头和尾:

 

ChannelHandler的种类

从上面DefaultChannelHandlerContext代码可以知道,Handler实际上分为两种,Inbound和Outbound,这一点也可以从ChannelHandler接口的子接口得到证明:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. public interface ChannelInboundHandler extends ChannelHandler {  
  2.   // ...  
  3. }  
  4.   
  5. public interface ChannelOutboundHandler extends ChannelHandler {  
  6.   // ...  
  7. }  

 

 

事件的传播

为了搞清楚事件如何在Pipeline里传播,让我们从Channel的抽象子类AbstractChannel开始,下面是AbstractChannel#write()方法的实现:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {  
  2.     // ...  
  3.     @Override  
  4.     public Channel write(Object msg) {  
  5.         return pipeline.write(msg);  
  6.     }  
  7.     // ...  
  8. }  


AbstractChannel直接调用了Pipeline的write()方法:

 

再看DefaultChannelPipeline的write()方法实现:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. final class DefaultChannelPipeline implements ChannelPipeline {  
  2.     // ...  
  3.     @Override  
  4.     public ChannelFuture write(Object msg) {  
  5.         return tail.write(msg);  
  6.     }  
  7.     // ...  
  8. }  


因为write是个outbound事件,所以DefaultChannelPipeline直接找到tail部分的context,调用其write()方法:

 

接着看DefaultChannelHandlerContext的write()方法:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {  
  2.     // ...  
  3.     @Override  
  4.     public ChannelFuture write(Object msg) {  
  5.         return write(msg, newPromise());  
  6.     }  
  7.   
  8.     @Override  
  9.     public ChannelFuture write(final Object msg, final ChannelPromise promise) {  
  10.         if (msg == null) {  
  11.             throw new NullPointerException("msg");  
  12.         }  
  13.   
  14.         validatePromise(promise, true);  
  15.   
  16.         write(msg, false, promise);  
  17.   
  18.         return promise;  
  19.     }  
  20.   
  21.     private void write(Object msg, boolean flush, ChannelPromise promise) {  
  22.         DefaultChannelHandlerContext next = findContextOutbound();  
  23.         next.invokeWrite(msg, promise);  
  24.         if (flush) {  
  25.             next.invokeFlush();  
  26.         }  
  27.     }  
  28.   
  29.     private DefaultChannelHandlerContext findContextOutbound() {  
  30.         DefaultChannelHandlerContext ctx = this;  
  31.         do {  
  32.             ctx = ctx.prev;  
  33.         } while (!ctx.outbound);  
  34.         return ctx;  
  35.     }  
  36.   
  37.     private void invokeWrite(Object msg, ChannelPromise promise) {  
  38.         try {  
  39.             ((ChannelOutboundHandler) handler).write(this, msg, promise);  
  40.         } catch (Throwable t) {  
  41.             notifyOutboundHandlerException(t, promise);  
  42.         }  
  43.     }  
  44.   
  45.     // ...  
  46. }  


context的write()方法沿着context链往前找,直至找到一个outbound类型的context为止,然后调用其invokeWrite()方法:

 

invokeWrite()接着调用handler的write()方法:

最后看看ChannelOutboundHandlerAdapter的write()方法实现:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {  
  2.     // ...  
  3.     @Override  
  4.     public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {  
  5.         ctx.write(msg, promise);  
  6.     }  
  7.     // ...  
  8. }  


默认的实现调用了context的write()方法而不做任何处理,这样write事件就沿着outbound链继续传播:

 

可见,Pipeline的事件传播,是靠Pipeline,Context和Handler共同协作完成的。

 

参考资料

netty.io

Netty in Action

Intercepting Filter

分享到:
评论

相关推荐

    DotNetty系列四:自定义协议,序列化类库MessagePack,项目代码

    管道(ChannelPipeline)是DotNetty的核心组件,它负责处理进来的网络事件,并按照预设的顺序传递给各个处理器(ChannelHandler)。 接下来,我们关注如何定义自定义协议。这通常涉及到解析和构建消息的逻辑。在...

    netty服务器解析16进制数据

    这些处理器可以被添加到Netty的管道(`ChannelPipeline`)中,以便在数据传输时自动应用。 6. **LIQUIDSOCKETSERVER 示例** 压缩包中的 "LIQUIDSOCKETSERVER" 文件可能是Netty服务器的源代码示例,它可能展示了...

    SocketIO-SocketIO-NettyClient&ServerMarshalingCode.zip

    在Netty服务器端,我们需要定义一个ChannelInitializer,它会在新的连接建立时初始化ChannelPipeline。在这个管道中,我们可以添加各种处理器,如解码器和编码器,来处理进来的和发送出去的数据。对于Marshaling编...

    第七章:编解码器Codec.pdf

    编解码器(Codec)是网络应用程序中非常重要的一部分,它负责将原始字节数据与自定义的消息对象进行互转。在Netty框架中,编解码器由两部分组成:Decoder(解码器)和Encoder(编码器)。解码器负责将消息从字节或...

    Netty 框架学习 —— 编解码器框架(csdn)————程序.pdf

    解码器的使用场景通常是在 `ChannelPipeline` 中,当需要对入站数据进行转换以适应后续处理器(ChannelInboundHandler)时。在 `ChannelPipeline` 中,你可以连接多个解码器以实现复杂的数据转换逻辑。例如,你可能...

    netty客户端和服务端通讯

    通过它,Handler 可以调用 Channel 的方法,或者向 ChannelPipeline 中的下一个 Handler 传递事件。 5. **Bootstrap 和 ServerBootstrap**:Bootstrap 用于创建客户端连接,ServerBootstrap 用于创建服务器。它们都...

    nettyinaction中文版.pdf

    在本章《Netty in Action》的中文版中,作者主要介绍了Netty框架中的核心类,包括Bootstrap、ServerBootstrap、EventLoop、EventLoopGroup、ChannelPipeline、ChannelFuture、ChannelInitializer和ChannelHandler等...

    netty编码器,解码器实例

    为了在Netty管道中使用这些编码器和解码器,我们需要将它们添加到 ChannelPipeline 中。例如: ```java ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("decoder", new CustomMessageDecoder()); ...

    TestNetty 一个小例子

    4. **ChannelHandler** 和 **ChannelPipeline**:ChannelHandler 处理 Channel 上的事件,ChannelPipeline 是 ChannelHandler 的链式结构,处理入站和出站事件。 5. **ByteBuf**:Netty 的高效字节缓冲区,替代了...

    Netty4.0学习笔记系列之二:Handler的执行顺序

    ChannelPipeline 可以理解为一系列 ChannelHandler 的容器,当数据通过 Channel 流动时,会依次经过 ChannelPipeline 中的每个 Handler。Handler 的执行顺序由它们在 Pipeline 中的位置决定,一般遵循“先进先出”...

    Netty中Marshalling编解码自定义栈应用

    然后,你可以在你的 ChannelPipeline 中添加这两个自定义编解码器,确保它们的顺序正确(编码器应该在解码器之前): ```java ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new ...

    Netty_Chat_server_client_src_java.zip_netty_netty html5 chat_sep

    Netty服务器端通常由多个组件构成,包括Bootstrap、ServerBootstrap、ChannelFuture、ChannelHandler和ChannelPipeline等。Bootstrap是服务器端启动器,用来配置服务器的连接参数,如绑定的IP地址和端口。...

    unit3.2.rar netty基础类netty基础类netty基础类netty基础类netty基础类

    `ChannelPipeline`则是一系列`ChannelHandler`的链表,负责在`Channel`上按顺序调用这些处理器,实现了数据的双向传递和事件的处理。 5. **Bootstrap 和 ServerBootstrap**: `Bootstrap`用于创建客户端连接,而`...

    netty学习之ServerChannel

    4. **ChannelPipeline**:ChannelPipeline是处理I/O事件的链条,它包含了一系列ChannelHandler。当数据从网络流入或流出时,它们会在pipeline中的各个handler之间传递,每个handler可以对其进行处理或转发。 5. **...

    netty服务器son解析

    最后,我们需要在服务器的 ChannelPipeline 中添加这个自定义的解码器: ```java ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())...

    译文-Netty教程

    它不仅支持传统的客户端-服务器模型,还能通过ChannelPipeline机制实现各种协议的编解码器,并将各种协议消息转换为统一的消息格式。Netty中的ChannelPipeline相当于一组拦截过滤器,用于在数据流经Channel时,对其...

    netty实现的聊天代码

    服务器启动时,会创建一个 `Bootstrap` 实例,绑定一个端口,并添加 `ChannelInitializer`,在这个初始化器中,我们可以设置 `ChannelPipeline`,将我们的 `ChannelHandler` 添加到管道中。当有新的连接建立时,...

    Netty in Action 2014 v10 MEAP

    3. 通道处理流程:Netty中的数据处理流程是通过ChannelPipeline来完成的,每个Channel都有一个与之关联的ChannelPipeline。当一个消息或特定的I/O事件被触发时,它会沿着ChannelPipeline传播,由ChannelHandler链...

    JavaNettyProj服务器与客户端.rar

    在JavaNettyProj中,服务器端(Server)会通过Bootstrap配置一个ServerBootstrap实例,绑定监听端口,并设置ChannelPipeline,这个管道会包含解码和编码的处理器,例如ByteToMessageDecoder和MessageToByteEncoder,...

Global site tag (gtag.js) - Google Analytics