- 浏览: 788308 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
萨琳娜啊:
Java读源码之Netty深入剖析网盘地址:https://p ...
Netty源码学习-FileRegion -
飞天奔月:
写得有趣 ^_^
那一年你定义了一个接口 -
GoldRoger:
第二个方法很好
java-判断一个自然数是否是某个数的平方。当然不能使用开方运算 -
bylijinnan:
<script>alert("close ...
自己动手实现Java Validation -
paul920531:
39行有个bug:"int j=new Random ...
java-蓄水池抽样-要求从N个元素中随机的抽取k个元素,其中N无法确定
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方法:
查看一下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方法:
-->FrameDecoder重写了messageReceived方法,在messageReceived里面,就会调用到文章开头提到的decode方法:
而callDecode方法的关键代码是这样的:
在unfoldAndFireMessageReceived方法里面,会调用Channels.fireMessageReceived,最后会调用ctx.sendUpstream,事件会交给下一个Handler来处理
在示例中,下一个Handler就是TimeClientHandler
因此,如果TimeDecoder(extends FrameDecoder)的decode方法返回了UnixTime对象,那TimeClientHandler就可以直接拿到并强制转换成UnixTime对象:
TimeDecoder:
TimeClientHandler:
pipeline里面对Upstream的处理,在handler链表里面,是从head到tail,因此TimeDecoder应在TimeClientHandler之前:
开发中,只需要重写FrameDecoder.decode方法就可以了
由于Netty接收到数据后,会不断触发整个Upstream的处理流程,像上面分析的那样,因此,decode方法就会不断被调用
最后一个问题,FrameDecoder是怎样保留之前接收到的数据呢?
原来FrameDecoder维护了一个ChannelBuffer(作为它的field),源码里命名为cumulation
cumulation会一直保留数据,并按需扩容,直到所需要的数据全部接收到达为止
看看源码:
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方法:
protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)2 { if (buffer.readableBytes() < 4) { return null; 3 } return buffer.readBytes(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会一直保留数据,并按需扩容,直到所需要的数据全部接收到达为止
看看源码:
//decode得到的结果可能是一个数组或者集合,如果unfold=true,则让每一个元素都触发一个fireMessageReceived事件 private boolean unfold; protected ChannelBuffer cumulation; //将每次接收到的数据累积起来,直到数据接收完全 private volatile ChannelHandlerContext ctx; //cumulation使用了CompositeChannelBuffer来避免“memory copy”(ChannelBuffers.wrappedBuffer) //cumulation是否需要开辟新内存空间并复制数据,取决于两个值: //1.copyThreshold是从cumulation的总大小来限制 //2.maxCumulationBufferComponents是从cumulation的component的个数来限制 //如果cumulation的大小超过此值,就把cumulation复制到一个新创建的ChannelBuffer里面 private int copyThreshold; //如果cumulation中component的个数超过此值,则像上面那样进行复制 private int maxCumulationBufferComponents; //这个方法体现了上面据说的第2个限制:maxCumulationBufferComponents protected ChannelBuffer appendToCumulation(ChannelBuffer input) { ChannelBuffer cumulation = this.cumulation; assert cumulation.readable(); if (cumulation instanceof CompositeChannelBuffer) { // Make sure the resulting cumulation buffer has no more than the configured components. CompositeChannelBuffer composite = (CompositeChannelBuffer) cumulation; if (composite.numComponents() >= maxCumulationBufferComponents) { cumulation = composite.copy(); } } this.cumulation = input = ChannelBuffers.wrappedBuffer(cumulation, input); return input; } //这个方法体现了上面据说的第1个限制:copyThreshold protected ChannelBuffer updateCumulation(ChannelHandlerContext ctx, ChannelBuffer input) { ChannelBuffer newCumulation; int readableBytes = input.readableBytes(); if (readableBytes > 0) { int inputCapacity = input.capacity(); //超限了 if (readableBytes < inputCapacity && inputCapacity > copyThreshold) { //newCumulationBuffer方法新建一个指定大小的ChannelBuffer cumulation = newCumulation = newCumulationBuffer(ctx, input.readableBytes()); cumulation.writeBytes(input); } else { if (input.readerIndex() != 0) { cumulation = newCumulation = input.slice(); } else { cumulation = newCumulation = input; } } } else { cumulation = newCumulation = null; } return newCumulation; } //unfold的用途 protected final void unfoldAndFireMessageReceived( ChannelHandlerContext context, SocketAddress remoteAddress, Object result) { if (unfold) { if (result instanceof Object[]) { for (Object r: (Object[]) result) { Channels.fireMessageReceived(context, r, remoteAddress); } } else if (result instanceof Iterable<?>) { for (Object r: (Iterable<?>) result) { Channels.fireMessageReceived(context, r, remoteAddress); } } else { Channels.fireMessageReceived(context, result, remoteAddress); } } else { Channels.fireMessageReceived(context, result, remoteAddress); } }
发表评论
-
TCP的TIME-WAIT
2014-04-23 16:35 1202原文连接:http://vincent.bernat.im/e ... -
《TCPIP详解卷1》学习-拥塞避免
2014-01-15 15:16 159拥塞避免算法、 ... -
Netty源码学习-HTTP-tunnel
2014-01-14 18:19 4309Netty关于HTTP tunnel的说明: http://d ... -
Netty源码学习-FileRegion
2013-12-31 17:17 5673今天看org.jboss.netty.example.http ... -
Netty源码学习-HttpChunkAggregator-HttpRequestEncoder-HttpResponseDecoder
2013-12-27 16:10 4099今天看Netty如何实现一个Http Server org.j ... -
Netty源码学习-ReadTimeoutHandler
2013-12-26 17:53 3852ReadTimeoutHandler的实现思 ... -
Netty学习笔记
2013-12-25 18:39 1491本文是阅读以下两篇文章时: http://seeallhear ... -
Netty源码学习-ChannelHandler
2013-12-25 18:12 1639一般来说,“有状态”的ChannelHandler不应 ... -
Netty源码学习-ServerBootstrap启动及事件处理过程
2013-12-19 20:11 10770Netty是采用了Reactor模式的多线程版本,建议先看下面 ... -
Netty源码学习-Java-NIO-Reactor
2013-12-19 18:21 4901Netty里面采用了NIO-based Reactor Pat ... -
Netty源码学习-ReplayingDecoder
2013-12-13 20:21 4271ReplayingDecoder是FrameDecoder的子 ... -
Netty源码学习-DefaultChannelPipeline2
2013-12-11 15:47 1292Netty3的API http://docs.jboss.or ... -
Netty源码学习-CompositeChannelBuffer
2013-12-06 15:54 2766CompositeChannelBuffer体现了Netty的 ... -
Netty源码学习-DelimiterBasedFrameDecoder
2013-12-05 18:36 9584看DelimiterBasedFrameDecoder的AP ... -
Netty源码学习-ObjectEncoder和ObjectDecoder
2013-12-05 16:06 5009Netty中传递对象的思路很直观: Netty中数据的传递是基 ... -
Netty源码学习-LengthFieldBasedFrameDecoder
2013-12-05 15:20 7327先看看LengthFieldBasedFrameDecoder ... -
Netty源码学习-DefaultChannelPipeline
2013-11-27 17:00 2247package com.ljn.channel; /** ...
相关推荐
netty-buffer-4.1.32.Final-sources.jar netty-buffer-4.1.32.Final.jar netty-build-22-sources.jar netty-build-22.jar netty-codec-4.1.32.Final-sources.jar netty-codec-4.1.32.Final.jar netty-codec-...
赠送jar包:netty-codec-mqtt-4.1.73.Final.jar; 赠送原API文档:netty-codec-mqtt-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-mqtt-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-transport-rxtx-4.1.74.Final.jar; 赠送原API文档:netty-transport-rxtx-4.1.74.Final-javadoc.jar; 赠送源代码:netty-transport-rxtx-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:...
赠送jar包:netty-transport-native-unix-common-4.1.73.Final.jar; 赠送原API文档:netty-transport-native-unix-common-4.1.73.Final-javadoc.jar; 赠送源代码:netty-transport-native-unix-common-4.1.73....
赠送jar包:netty-resolver-dns-4.1.65.Final.jar; 赠送原API文档:netty-resolver-dns-4.1.65.Final-javadoc.jar; 赠送源代码:netty-resolver-dns-4.1.65.Final-sources.jar; 赠送Maven依赖信息文件:netty-...
赠送jar包:netty-transport-classes-epoll-4.1.73.Final.jar; 赠送原API文档:netty-transport-classes-epoll-4.1.73.Final-javadoc.jar; 赠送源代码:netty-transport-classes-epoll-4.1.73.Final-sources.jar;...
赠送jar包:netty-codec-dns-4.1.65.Final.jar; 赠送原API文档:netty-codec-dns-4.1.65.Final-javadoc.jar; 赠送源代码:netty-codec-dns-4.1.65.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-dns-...
赠送jar包:netty-codec-http2-4.1.74.Final.jar; 赠送原API文档:netty-codec-http2-4.1.74.Final-javadoc.jar; 赠送源代码:netty-codec-http2-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-dns-4.1.65.Final.jar; 赠送原API文档:netty-codec-dns-4.1.65.Final-javadoc.jar; 赠送源代码:netty-codec-dns-4.1.65.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-dns-...
赠送jar包:netty-codec-haproxy-4.1.73.Final.jar; 赠送原API文档:netty-codec-haproxy-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-haproxy-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-...
赠送jar包:netty-transport-classes-epoll-4.1.74.Final.jar; 赠送原API文档:netty-transport-classes-epoll-4.1.74.Final-javadoc.jar; 赠送源代码:netty-transport-classes-epoll-4.1.74.Final-sources.jar;...
赠送jar包:netty-resolver-dns-4.1.65.Final.jar; 赠送原API文档:netty-resolver-dns-4.1.65.Final-javadoc.jar; 赠送源代码:netty-resolver-dns-4.1.65.Final-sources.jar; 赠送Maven依赖信息文件:netty-...
赠送jar包:netty-codec-http2-4.1.73.Final.jar; 赠送原API文档:netty-codec-http2-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-http2-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-transport-classes-epoll-4.1.73.Final.jar; 赠送原API文档:netty-transport-classes-epoll-4.1.73.Final-javadoc.jar; 赠送源代码:netty-transport-classes-epoll-4.1.73.Final-sources.jar;...
赠送jar包:netty-transport-native-unix-common-4.1.74.Final.jar; 赠送原API文档:netty-transport-native-unix-common-4.1.74.Final-javadoc.jar; 赠送源代码:netty-transport-native-unix-common-4.1.74....
赠送jar包:netty-transport-native-unix-common-4.1.73.Final.jar; 赠送原API文档:netty-transport-native-unix-common-4.1.73.Final-javadoc.jar; 赠送源代码:netty-transport-native-unix-common-4.1.73....
赠送jar包:netty-codec-redis-4.1.73.Final.jar; 赠送原API文档:netty-codec-redis-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-redis-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-http-4.1.27.Final.jar; 赠送原API文档:netty-codec-http-4.1.27.Final-javadoc.jar; 赠送源代码:netty-codec-http-4.1.27.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-resolver-dns-4.1.73.Final.jar; 赠送原API文档:netty-resolver-dns-4.1.73.Final-javadoc.jar; 赠送源代码:netty-resolver-dns-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-...
赠送jar包:netty-transport-native-unix-common-4.1.68.Final.jar; 赠送原API文档:netty-transport-native-unix-common-4.1.68.Final-javadoc.jar; 赠送源代码:netty-transport-native-unix-common-4.1.68....