netty 概述(转) -凯发k8网页登录

standing on the shoulders of giants
posts - 481, comments - 486, trackbacks - 0, articles - 1
  凯发k8网页登录-凯发天生赢家一触即发官网 :: 凯发k8网页登录首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

netty 概述(转)

posted on 2016-07-13 09:49 疯狂 阅读(893) 评论(0)  编辑  收藏 所属分类: netty
转载自http://blog.csdn.net/zxhoo/article/details/17264263

netty4

是一个和类似的java nio框架,目前的最新版本是,这两个框架的主要作者好像都是。

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。

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可以看出来。

调用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组成了一个双向链表:

再来看看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链的头和尾:

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()方法:

final class defaultchannelpipeline implements channelpipeline {     // ...     @override     public channelfuture write(object msg) {         return tail.write(msg);     }     // ... }

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

接着看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()方法:

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

最后看看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链继续传播:

可见,pipeline的事件传播,是靠pipeline,context和handler共同协作完成的。


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


网站导航:
              
 
网站地图