Netty3源码学习-FrameDecoder_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Netty3源码学习-FrameDecoder

Netty3源码学习-FrameDecoder

 2013/11/28 21:33:43  bylijinnan  程序员俱乐部  我要评论(0)
  • 摘要:Netty3.x的userguide里FrameDecoder的例子,有几个疑问:1.文档说:FrameDecodercallsdecodemethodwithaninternallymaintainedcumulativebufferwhenevernewdataisreceived.为什么每次有新数据到达时,都会调用decode方法?2.Decoder与其他handler在pipeline的顺序是怎样的?谁先谁后?3.所要接收的数据可能要经过多次才能接收完全,那这之前数据是如何保留
  • 标签:学习 源码 net
Netty 3.x的user guide里FrameDecoder的例子,有几个疑问:
1.文档说:FrameDecoder calls decode method with an internally maintained cumulative buffer whenever new data is received.
为什么每次有新数据到达时,都会调用decode方法?
2.Decoder与其他handler在pipeline的顺序是怎样的?谁先谁后?
3.所要接收的数据可能要经过多次才能接收完全,那这之前数据是如何保留?

先说结论:
1.因为每一次消息到达时都会触发pipeline的Upstream处理流程,最终会调用handler的messageReceived方法,而FrameDecoder的messageRecieved方法会调用decode方法
2.Decoder在前
3.FrameDecoder维护了一个ChannelBuffer(作为它的field)

文档中TimeDecoder的decode方法:
class="java" name="code">protected Object decode(
            ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)2 {
            
        if (buffer.readableBytes() < 4) {
            return null; 3
        }
        
        return buffer.readBytes(4);4
    }



查看一下FrameDecoder 源码:

FrameDecoder继承自SimpleChannelUpstreamHandler,而SimpleChannelUpstreamHandler实现了ChannelUpstreamHandler接口
ChannelUpstreamHandler很简单,只定义了一个handleUpstream方法

理解FrameDecoder,首先要理解Netty的event在pipeline里面是怎么流转处理的,可以参看这篇博文http://bylijinnan.iteye.com/blog/1981763:
其次,理解Upstream和Downstream
我是这样理解的,对于Handler来说,Handler接收的消息是Upstream;从Handler发出的消息,是Downstream
然后,我们就可以理解FrameDecoder的流程了:

-->ChannlPipeline 开始处理Upstream,会调用sendUpstream方法,
-->调用SimpleChannelUpstreamHandler(也就是FrameDecoder)的handleUpstream方法
而SimpleChannelUpstreamHandler的handleUpstream会触发messageReceived方法:
public void handleUpstream(
				ChannelHandlerContext ctx, ChannelEvent e) throws Exception {

			if (e instanceof MessageEvent) {
				messageReceived(ctx, (MessageEvent) e);
			} 
			/*omit others*/

-->FrameDecoder重写了messageReceived方法,在messageReceived里面,就会调用到文章开头提到的decode方法:
public void messageReceived(
            ChannelHandlerContext ctx, MessageEvent e) {
				
				/*只保留关键代码*/
				ChannelBuffer input = (ChannelBuffer) e.getMessage();
				callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
                updateCumulation(ctx, input);
		}
	

而callDecode方法的关键代码是这样的:
private void callDecode(
            ChannelHandlerContext context, Channel channel,
            ChannelBuffer cumulation, SocketAddress remoteAddress) throws Exception {

			while (cumulation.readable()) {
				Object frame = decode(context, channel, cumulation);
				unfoldAndFireMessageReceived(context, remoteAddress, frame);
			}
		}

在unfoldAndFireMessageReceived方法里面,会调用Channels.fireMessageReceived,最后会调用ctx.sendUpstream,事件会交给下一个Handler来处理
在示例中,下一个Handler就是TimeClientHandler
因此,如果TimeDecoder(extends FrameDecoder)的decode方法返回了UnixTime对象,那TimeClientHandler就可以直接拿到并强制转换成UnixTime对象:
TimeDecoder:
protected Object decode(
				ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) {
			if (buffer.readableBytes() < 4) {
				return null;
			}
			return new UnixTime(buffer.readInt());1
		}

TimeClientHandler:
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
			UnixTime m = (UnixTime) e.getMessage();
		}


pipeline里面对Upstream的处理,在handler链表里面,是从head到tail,因此TimeDecoder应在TimeClientHandler之前:
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() {
                return Channels.pipeline(
                        new TimeDecoder(),
                        new TimeClientHandler());
            }
        });


开发中,只需要重写FrameDecoder.decode方法就可以了
由于Netty接收到数据后,会不断触发整个Upstream的处理流程,像上面分析的那样,因此,decode方法就会不断被调用


最后一个问题,FrameDecoder是怎样保留之前接收到的数据呢?
原来FrameDecoder维护了一个ChannelBuffer(作为它的field),源码里命名为cumulation
cumulation会一直保留数据,并按需扩容,直到所需要的数据全部接收到达为止







发表评论
用户名: 匿名