疯狂

STANDING ON THE SHOULDERS OF GIANTS
posts - 480, comments - 486, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Netty 概述(转)

Posted on 2016-07-13 09:49 疯狂 阅读(274) 评论(0)  编辑  收藏 所属分类: netty
转载自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。

Netty中的所有handler都实现自ChannelHandler接口。按照输出输出来分,分为ChannelInboundHandler、ChannelOutboundHandler两大类

ChannelInboundHandler对从客户端发往服务器的报文进行处理,一般用来执行解码、读取客户端数据、进行业务处理等;

ChannelOutboundHandler对从服务器发往客户端的报文进行处理,一般用来进行编码、发送报文到客户端。

ChannelPipeline

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

netty概述

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

ChannelPipeline addFirst(String name, ChannelHandler handler); ChannelPipeline addLast(String name, ChannelHandler handler); ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler); ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler); ChannelPipeline remove(ChannelHandler handler); ChannelHandler remove(String name); ChannelHandler removeFirst(); ChannelHandler removeLast(); ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler); ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler); ChannelHandler first(); ChannelHandler last(); ChannelHandler get(String name);

ChannelHandlerContext

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

netty概述

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

ChannelPipeline和ChannelHandlerContext默认实现

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

final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {      volatile DefaultChannelHandlerContext next;     volatile DefaultChannelHandlerContext prev;      private final boolean inbound;     private final boolean outbound;     private final AbstractChannel channel;     private final DefaultChannelPipeline pipeline;     private final String name;     private final ChannelHandler handler;     private boolean removed;      // ... }

final class DefaultChannelPipeline implements ChannelPipeline {     // ...      final DefaultChannelHandlerContext head;     final DefaultChannelHandlerContext tail;      // ... }

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

netty概述

再来看看DefaultChannelPipeline的构造函数:

    public DefaultChannelPipeline(AbstractChannel channel) {         if (channel == null) {             throw new NullPointerException("channel");         }         this.channel = channel;          TailHandler tailHandler = new TailHandler();         tail = new DefaultChannelHandlerContext(this, null, generateName(tailHandler), tailHandler);          HeadHandler headHandler = new HeadHandler(channel.unsafe());         head = new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler);          head.next = tail;         tail.prev = head;     }

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

netty概述

ChannelHandler的种类

Netty中的所有handler都实现自ChannelHandler接口。按照输出输出来分,分为ChannelInboundHandler、ChannelOutboundHandler两大类。ChannelInboundHandler对从客户端发往服务器的报文进行处理,一般用来执行解码、读取客户端数据、进行业务处理等;ChannelOutboundHandler对从服务器发往客户端的报文进行处理,一般用来进行编码、发送报文到客户端。

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

public interface ChannelInboundHandler extends ChannelHandler {   // ... }  public interface ChannelOutboundHandler extends ChannelHandler {   // ... }


事件的传播

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

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {     // ...     @Override     public Channel write(Object msg) {         return pipeline.write(msg);     }     // ... }

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

netty概述

final class DefaultChannelPipeline implements ChannelPipeline {     // ...     @Override     public ChannelFuture write(Object msg) {         return tail.write(msg);     }     // ... }

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

netty概述

接着看DefaultChannelHandlerContext的write()方法:

final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {     // ...     @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");         }          validatePromise(promise, true);          write(msg, false, promise);          return promise;     }      private void write(Object msg, boolean flush, ChannelPromise promise) {         DefaultChannelHandlerContext next = findContextOutbound();         next.invokeWrite(msg, promise);         if (flush) {             next.invokeFlush();         }     }      private DefaultChannelHandlerContext findContextOutbound() {         DefaultChannelHandlerContext ctx = this;         do {             ctx = ctx.prev;         } while (!ctx.outbound);         return ctx;     }      private void invokeWrite(Object msg, ChannelPromise promise) {         try {             ((ChannelOutboundHandler) handler).write(this, msg, promise);         } catch (Throwable t) {             notifyOutboundHandlerException(t, promise);         }     }      // ... }

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

netty概述

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

netty概述

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

public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {     // ...     @Override     public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {         ctx.write(msg, promise);     }     // ... }

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

netty概述

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


只有注册用户登录后才能发表评论。


网站导航: