- 浏览: 787288 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
萨琳娜啊:
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无法确定
ReplayingDecoder是FrameDecoder的子类,不熟悉FrameDecoder的,可以先看看
http://bylijinnan.iteye.com/blog/1982618
API说,ReplayingDecoder简化了操作,比如:
FrameDecoder在decode时,需要判断数据是否接收完全:
而ReplayingDecoder则隐藏了这些判断,好像数据已经接收完全了一样:
可见,ReplayingDecoder使用起来要简单、直观
除此之外,
很多时候frame的结构不会是“length + content”这么简单,如果结构复杂了,
FrameDecoder的if语句就会非常多,且先到达的sub-frame就会被多次decode
ReplayingDecoder允许用户自定义state,表示decode到哪一部分了,从而下
一次数据到达时,直接从nextState开始decode
那ReplayingDecoder这是怎么做到“好像数据已经接收完全了一样”?
事实上它跟FrameDecoder的思路是一样的,只是它在数据接收不完全时,
“悄悄地失败”。这主要是通过ReplayingDecoderBuffer来实现的:
ReplayingDecoder的使用,API给出了一个简单的例子:
注意到上面的switch语句是不需要break的,因为case READ_LENGTH后:
1.如果数据不充足,那就会在buf.readBytes(length)里面抛出ReplayError,相当于有了break语句
2.如果数据充足,那就接着decode,最终成功并 return frame
除了API以外,下面这两篇文章写得非常好:
http://biasedbit.com/netty-tutorial-replaying-decoder/
http://biasedbit.com/an-enhanced-version-of-replayingdecoder-for-netty/
其中第二个例子,文章中给的代码不是很完整,我补全并做了一个简单的测试:
https://github.com/bylijinnan/nettyLearn/tree/master/ljn-netty3-learn/src/main/java/com/ljn/handler/replay
http://bylijinnan.iteye.com/blog/1982618
API说,ReplayingDecoder简化了操作,比如:
FrameDecoder在decode时,需要判断数据是否接收完全:
public class IntegerHeaderFrameDecoder extends FrameDecoder { protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception { if (buf.readableBytes() < 4) { return null; } buf.markReaderIndex(); int length = buf.readInt(); if (buf.readableBytes() < length) { buf.resetReaderIndex(); return null; } return buf.readBytes(length); } }
而ReplayingDecoder则隐藏了这些判断,好像数据已经接收完全了一样:
public class IntegerHeaderFrameDecoder extends ReplayingDecoder<VoidEnum> { protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf, VoidEnum state) throws Exception { int length = buf.readInt(); return buf.readBytes(length); } }
可见,ReplayingDecoder使用起来要简单、直观
除此之外,
很多时候frame的结构不会是“length + content”这么简单,如果结构复杂了,
FrameDecoder的if语句就会非常多,且先到达的sub-frame就会被多次decode
ReplayingDecoder允许用户自定义state,表示decode到哪一部分了,从而下
一次数据到达时,直接从nextState开始decode
那ReplayingDecoder这是怎么做到“好像数据已经接收完全了一样”?
事实上它跟FrameDecoder的思路是一样的,只是它在数据接收不完全时,
“悄悄地失败”。这主要是通过ReplayingDecoderBuffer来实现的:
class ReplayingDecoderBuffer implements ChannelBuffer { private static final Error REPLAY = new ReplayError(); private final ReplayingDecoder<?> parent; private boolean terminated; //ReplayingDecoder作为参数 ReplayingDecoderBuffer(ReplayingDecoder<?> parent) { this.parent = parent; } /*ReplayingDecoderBuffer实际上是FrameDecoder里面的cumulation(类型为ChannelBuffer) FrameDecoder里面,对数据的累积接收,以及数据的读取,都是在cumulation, 而ReplayingDecoderBuffer对cumulation进行了封装,在数据不完全时,读取操作都会抛出Error */ private ChannelBuffer buf() { return parent.internalBuffer(); } public byte getByte(int index) { checkIndex(index); return buf().getByte(index); } //数据接收不完全时,抛出Error,在ReplayingDecoder里捕获 private void checkIndex(int index) { if (index > buf().writerIndex()) { throw REPLAY; } }
public abstract class ReplayingDecoder<T extends Enum<T>> extends FrameDecoder { //创建了ReplayingDecoderBuffer private final ReplayingDecoderBuffer replayable = new ReplayingDecoderBuffer(this); private T state; //标记着下一次数据读取的开始位置,也代表着已经decode到哪一部分了 private int checkpoint; protected void checkpoint() { ChannelBuffer cumulation = this.cumulation; if (cumulation != null) { checkpoint = cumulation.readerIndex(); } else { checkpoint = -1; // buffer not available (already cleaned up) } } protected void checkpoint(T state) { checkpoint(); setState(state); } protected T setState(T newState) { T oldState = state; state = newState; return oldState; } //这个方法交由子类实现,子类可以定义更详细、语义更丰富的state protected abstract Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, T state) throws Exception; //重点在这个方法,注意对ReplayError的处理 private void callDecode( ChannelHandlerContext context, Channel channel, ChannelBuffer input, ChannelBuffer replayableInput, SocketAddress remoteAddress) throws Exception { while (input.readable()) { int oldReaderIndex = checkpoint = input.readerIndex(); Object result = null; T oldState = state; try { //如果数据接收还不完全,decode方法就会抛出ReplayError //因为decode方法会调用replayableInput(类型为ReplayingDecoderBuffer)的getXXX方法 result = decode(context, channel, replayableInput, state); if (result == null) { //省略 } } catch (ReplayError replay) { //数据不充足,回退到checkpoint,下一次messageReceived再试 // Return to the checkpoint (or oldPosition) and retry. int checkpoint = this.checkpoint; if (checkpoint >= 0) { input.readerIndex(checkpoint); } else { // Called by cleanup() - no need to maintain the readerIndex // anymore because the buffer has been released already. } } if (result == null) { // Seems like more data is required. // Let us wait for the next notification. break; } // A successful decode unfoldAndFireMessageReceived(context, remoteAddress, result); } }
ReplayingDecoder的使用,API给出了一个简单的例子:
public class IntegerHeaderFrameDecoder extends ReplayingDecoder<MyDecoderState> { private int length; public IntegerHeaderFrameDecoder() { // Set the initial state. super(MyDecoderState.READ_LENGTH); } protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf, MyDecoderState state) throws Exception { switch (state) { case READ_LENGTH: length = buf.readInt(); //设置下一次的decode从哪一个state开始 checkpoint(MyDecoderState.READ_CONTENT); case READ_CONTENT: ChannelBuffer frame = buf.readBytes(length); checkpoint(MyDecoderState.READ_LENGTH); return frame; default: throw new Error("Shouldn't reach here."); } } }
注意到上面的switch语句是不需要break的,因为case READ_LENGTH后:
1.如果数据不充足,那就会在buf.readBytes(length)里面抛出ReplayError,相当于有了break语句
2.如果数据充足,那就接着decode,最终成功并 return frame
除了API以外,下面这两篇文章写得非常好:
http://biasedbit.com/netty-tutorial-replaying-decoder/
http://biasedbit.com/an-enhanced-version-of-replayingdecoder-for-netty/
其中第二个例子,文章中给的代码不是很完整,我补全并做了一个简单的测试:
https://github.com/bylijinnan/nettyLearn/tree/master/ljn-netty3-learn/src/main/java/com/ljn/handler/replay
发表评论
-
TCP的TIME-WAIT
2014-04-23 16:35 1198原文连接:http://vincent.bernat.im/e ... -
《TCPIP详解卷1》学习-拥塞避免
2014-01-15 15:16 159拥塞避免算法、 ... -
Netty源码学习-HTTP-tunnel
2014-01-14 18:19 4304Netty关于HTTP tunnel的说明: http://d ... -
Netty源码学习-FileRegion
2013-12-31 17:17 5661今天看org.jboss.netty.example.http ... -
Netty源码学习-HttpChunkAggregator-HttpRequestEncoder-HttpResponseDecoder
2013-12-27 16:10 4089今天看Netty如何实现一个Http Server org.j ... -
Netty源码学习-ReadTimeoutHandler
2013-12-26 17:53 3838ReadTimeoutHandler的实现思 ... -
Netty学习笔记
2013-12-25 18:39 1488本文是阅读以下两篇文章时: http://seeallhear ... -
Netty源码学习-ChannelHandler
2013-12-25 18:12 1635一般来说,“有状态”的ChannelHandler不应 ... -
Netty源码学习-ServerBootstrap启动及事件处理过程
2013-12-19 20:11 10764Netty是采用了Reactor模式的多线程版本,建议先看下面 ... -
Netty源码学习-Java-NIO-Reactor
2013-12-19 18:21 4895Netty里面采用了NIO-based Reactor Pat ... -
Netty源码学习-DefaultChannelPipeline2
2013-12-11 15:47 1285Netty3的API http://docs.jboss.or ... -
Netty源码学习-CompositeChannelBuffer
2013-12-06 15:54 2762CompositeChannelBuffer体现了Netty的 ... -
Netty源码学习-DelimiterBasedFrameDecoder
2013-12-05 18:36 9562看DelimiterBasedFrameDecoder的AP ... -
Netty源码学习-ObjectEncoder和ObjectDecoder
2013-12-05 16:06 5007Netty中传递对象的思路很直观: Netty中数据的传递是基 ... -
Netty源码学习-LengthFieldBasedFrameDecoder
2013-12-05 15:20 7308先看看LengthFieldBasedFrameDecoder ... -
Netty源码学习-FrameDecoder
2013-11-28 18:38 3939Netty 3.x的user guide里FrameDecod ... -
Netty源码学习-DefaultChannelPipeline
2013-11-27 17:00 2243package 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-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-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-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-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-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....
赠送jar包:netty-codec-mqtt-4.1.74.Final.jar; 赠送原API文档:netty-codec-mqtt-4.1.74.Final-javadoc.jar; 赠送源代码:netty-codec-mqtt-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...
赠送jar包:netty-codec-http-4.1.68.Final.jar; 赠送原API文档:netty-codec-http-4.1.68.Final-javadoc.jar; 赠送源代码:netty-codec-http-4.1.68.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...