范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

netty系列之netty中的自动解码器ReplayingDecoder

  简介
  netty提供了一个从ByteBuf到用户自定义的message的解码器叫做ByteToMessageDecoder,要使用这个decoder,我们需要继承这个decoder,并实现decode方法,从而在这个方法中实现ByteBuf中的内容到用户自定义message对象的转换。
  那么在使用ByteToMessageDecoder的过程中会遇到什么问题呢?为什么又会有一个ReplayingDecoder呢?带着这个问题我们一起来看看吧。 ByteToMessageDecoder可能遇到的问题
  要想实现自己的解码器将ByteBuf转换成为自己的消息对象,可以继承ByteToMessageDecoder,然后实现其中的decode方法即可,先来看下decode方法的定义:      protected void decode(ChannelHandlerContext ctx,                              ByteBuf buf, List out) throws Exception
  输入的参数中buf是要解码的ByteBuf,out是解码过后的对象列表,我们需要把ByteBuf中的数据转换成为我们自己的对象加入out的list中。
  那么这里可能会遇到一个问题,因为我们在调用decode方法的时候buf中的数据可能还没有准备好,比如我们需要一个Integer,但是buf中的数据不够一个整数,那么就需要一些buf中数据逻辑的判断,我们以一个带有消息长度的Buf对象来描述一下这个过程。
  所谓带有消息长度的Buf对象,就是说Buf消息中的前4位,构成了一个整数,这个整数表示的是buf中后续消息的长度。
  所以我们读取消息进行转换的流程是,先读取前面4个字节,得到消息的长度,然后再读取该长度的字节,这就是我们真正要获取的消息内容。
  来看一下如果是继承自ByteToMessageDecoder应该怎么实现这个逻辑呢?    public class IntegerHeaderFrameDecoder extends ByteToMessageDecoder {        @Override      protected void decode(ChannelHandlerContext ctx,                              ByteBuf buf, List out) throws Exception {         if (buf.readableBytes() < 4) {           return;        }         buf.markReaderIndex();        int length = buf.readInt();         if (buf.readableBytes() < length) {           buf.resetReaderIndex();           return;        }         out.add(buf.readBytes(length));      }    }
  在decode中,我们首先需要判断buf中可读的字节有没有4个,没有的话直接返回。如果有,则先读取这4个字节的长度,然后再判断buf中的可读字节是否小于应该读取的长度,如果小于,则说明数据还没有准备好,需要调用resetReaderIndex进行重置。
  最后,如果所有的条件都满足,才真正进行读取工作。
  有没有一个办法可以不提前进行判断,可以直接按照自己想要的内容来读取buf的方式呢?答案就是ReplayingDecoder。
  我们先来看一下上面的例子用ReplayingDecoder重写是什么情况:    public class IntegerHeaderFrameDecoder         extends ReplayingDecoder {       protected void decode(ChannelHandlerContext ctx,                              ByteBuf buf, List out) throws Exception {         out.add(buf.readBytes(buf.readInt()));      }    }
  使用ReplayingDecoder,我们可以忽略buf是否已经接收到了足够的可读数据,直接读取即可。
  相比之下ReplayingDecoder非常的简单。接下来,我们来探究一下ReplayingDecoder的实现原理。 ReplayingDecoder的实现原理
  ReplayingDecoder实际上是ByteToMessageDecoder的一个子类,它的定义如下: public abstract class ReplayingDecoder extends ByteToMessageDecoder
  在ByteToMessageDecoder中,最重要的方法是channelRead,在这个方法中实际调用了 callDecode(ctx, cumulation, out);  来实现cumulation到out的解码过程。
  ReplayingDecoder的秘密就在于对这个方法的重写,我们来看下这个方法的具体实现:    protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List out) {         replayable.setCumulation(in);         try {             while (in.isReadable()) {                 int oldReaderIndex = checkpoint = in.readerIndex();                 int outSize = out.size();                 if (outSize > 0) {                     fireChannelRead(ctx, out, outSize);                     out.clear();                     if (ctx.isRemoved()) {                         break;                     }                     outSize = 0;                 }                 S oldState = state;                 int oldInputLength = in.readableBytes();                 try {                     decodeRemovalReentryProtection(ctx, replayable, out);                     if (ctx.isRemoved()) {                         break;                     }                     if (outSize == out.size()) {                         if (oldInputLength == in.readableBytes() && oldState == state) {                             throw new DecoderException(                                     StringUtil.simpleClassName(getClass()) + ".decode() must consume the inbound " +                                     "data or change its state if it did not decode anything.");                         } else {                             continue;                         }                     }                 } catch (Signal replay) {                     replay.expect(REPLAY);                     if (ctx.isRemoved()) {                         break;                     }                      // Return to the checkpoint (or oldPosition) and retry.                     int checkpoint = this.checkpoint;                     if (checkpoint >= 0) {                         in.readerIndex(checkpoint);                     } else {                     }                     break;                 }                 if (oldReaderIndex == in.readerIndex() && oldState == state) {                     throw new DecoderException(                            StringUtil.simpleClassName(getClass()) + ".decode() method must consume the inbound data " +                            "or change its state if it decoded something.");                 }                 if (isSingleDecode()) {                     break;                 }             }         } catch (DecoderException e) {             throw e;         } catch (Exception cause) {             throw new DecoderException(cause);         }     }
  这里的实现和ByteToMessageDecoder不同的是ReplayingDecoder中定义了一个checkpoint,这个checkpint是在尝试进行数据解码之初设置的: int oldReaderIndex = checkpoint = in.readerIndex();
  如果是在解码的过程中出现了异常,则使用checkpoint重置index:     int checkpoint = this.checkpoint;          if (checkpoint >= 0) {             in.readerIndex(checkpoint);         } else {     }
  这里捕获的异常是Signal,Signal是什么呢?
  Signal是一个Error对象: public final class Signal extends Error implements Constant
  这个异常是从replayable中抛出来的。
  replayable是一个特有的ByteBuf对象,叫做ReplayingDecoderByteBuf: final class ReplayingDecoderByteBuf extends ByteBuf
  在ReplayingDecoderByteBuf中定义了Signal属性:     private static final Signal REPLAY = ReplayingDecoder.REPLAY;
  这个Signal异常是从ReplayingDecoderByteBuf中的get方法中抛出的,这里以getInt为例,看一下异常是如何抛出的:     public int getInt(int index) {         checkIndex(index, 4);         return buffer.getInt(index);     }
  getInt方法首先会去调用checkIndex方法进行buff中的长度检测,如果小于要读取的长度,则会抛出异常REPLAY:     private void checkIndex(int index, int length) {         if (index + length > buffer.writerIndex()) {             throw REPLAY;         }     }
  这就是Signal异常的由来。 总结
  以上就是对ReplayingDecoder的介绍,虽然ReplayingDecoder好用,但是从它的实现可以看出,ReplayingDecoder是通过抛出异常来不断的重试,所以在某些特殊的情况下会造成性能的下降。
  也就是说在减少我们代码量的同时,降低了程序的执行效率。看来要想马儿跑又想马儿不吃草,这样的好事是不可能的了。 本文已收录于 http://www.flydean.com/14-4-netty-replayingdecoder/
  最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
  欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
国产三巨头厮杀!华为P50Pro一加9ProFindX3Pro,谁更值得入手3C毒物独家报道国产旗舰手机无论是在外观设计,还是在硬件配置方面,都已经有了很大提升,国产旗舰手机就算是和三星iPhone等这些国际品牌相比,差距也已经变得很小,而且甚至有赶超的趋6大快递巨头重大改变!数百万人将受益同一时间,上调派费!即将到来的9月,将迎来一个重大改变。近日,国内6家头部快递公司先后宣布上调快递员的派件费。最先领头的是中通,该公司在内网宣布自9月1日起,全网末端派费每票上涨0刚加完碳粉,为什么打印机又提示碳粉不足?两个原因很关键点击上方关注绘威打印,我专业,您轻松!不少人有过这样的经历,明明刚加过碳粉,才打印了没几张,打印机又开始提醒碳粉不足了!这时候,不少打印机小白就会开始怀疑,是不是商家产品质量有问题数字认证牵头承担的十三五国家重点研发计划项目顺利通过验收近日,北京数字认证(300579)股份有限公司牵头承担的十三五国家重点研发计划网络空间安全重点专项项目基于国产密码算法的服务认证与证明关键技术正式通过验收。项目执行期间,数字认证与红米k50小米12系列发布时间确定,部分配置曝光微博知名数码博主数码闲聊站最新消息,小米12系列和红米k50系列部分新机已备案。现有情报可知,小米12系列依然首发高通新型处理器骁龙898,该芯片为三星4nm工艺制程,安兔兔跑分有88度电行驶650公里,天窗比你家门还大,爱驰U6解析88度电行驶650公里,天窗比你家门还大,爱驰U6解析先说句题外话,我未入行时仅知道两家造车新势力,当然,那时候还不了解新势力的意思,仅知道一个是蔚来,另一个是爱驰。对于蔚来的了解特斯拉得克萨斯州超级工厂已开始试生产ModelY稿源TechWeb特斯拉位于得克萨斯州奥斯汀的超级工厂自去年7月份确定并动工建设以来,已有13个月,其中的一片厂房已基本建成,大量的生产设备也已准备就绪,而在本月初,有报道称这一超蓄势待发,利尔达拥抱AI市场新机遇近几年,随着AI技术的日益成熟,产业政策的持续出台,垂直行业应用的逐步落地,产业资本的持续投入,AI应用进入高速发展的快车道。AI市场的每一次变动都孕育着机遇,利尔达以现状分析为切狗狗币有没有可能和比特币一样,一枚值几万美金?先表明立场狗狗币和比特币根本没法比较。就叫山寨货而已,山寨的想要以假乱真,你以为你在读红楼梦啊假作真时真亦假,无为有处有还无。其二比特币已经占领了投资机构的共识,占领投资机构的心智这就是汽车机器人?来看看面向未来的汽车吧8月18日,百度联合央视新闻举办百度世界大会至今,百度世界大会已连续举办15届,每次大会都将展示百度人工智能在出行生活产业自主创新科技等领域的成果和应用。这次大会自然也不例外。在大vivoX70pro荣耀50新配色手机外观越来越个性了现在的手机外形大同小异,特别是键盘滑盖设计消失后,几乎都是方方正正矩形的样子。也许是厂商不堪寂寞,想在茫茫机海脱颖而出,毕竟相对于性能续航等手机外观才是消费者第一眼印象。手机正面是
iQOO8评测直屏电竞旗舰,更是不容低估的标准版2KLTPO屏幕超声波3D广域指纹50W无线闪充定制双主摄太多的光环加持,让今年的iQOO8Pro成为大众焦点,也让同系列的标准版被不少人忽视,但等到真正上手后你就会发现,看上去没荣耀60Pro规格参数曝光外观,参数进一步升级,不愧是荣耀无人不晓,HONOR是一家深受消费者喜爱的手机厂商,也非常愿意投资产品创新。所以,HONOR为行业带来了许多广受好评的产品。比如荣耀8荣耀V30Pro和荣耀50系列等。这些产品在设千元机首选红米?对比同价位荣耀机型,差距实在太大了说到千元机,很多人想到的品牌就是红米。作为小米的子品牌,红米在千元机市场一直拥有绝对的统治地位。相对低廉的价格使得千元机拥有庞大的用户,千元市场也成为手机品牌必争的价位段。其它品牌华为nova9芯片确定!荣耀50同款,但不支持5G近日网上曝光了华为nova9系列智能手机的芯片规格,该系列机器将采用骁龙778G芯片的4G版本,虽然骁龙778G芯片内置了5G基带,但是由于射频芯片等元器件的缺失,华为依旧没有办法外卖员发明超级电动车,从山东跑到浙江,网友大开眼界外卖行业的出现改变了人们的生活方式,现在外卖已经成为了许多年轻人生活中不可或缺的组成部分,年轻人工作繁忙,没有时间做饭,大家只需要打开手机点个外卖就能吃到热气腾腾的饭。外卖平台的出电信推出全新5G手机卡,69元60G通用流量,老用户直呼划算自2019年三大运营商正式商用5G网络之后,5G便成为大家茶余饭后讨论的热点话题,但在运营商公布首批5G套餐价格之后让不少人都避而远之,因为三大运营商的5G套餐价格都为128元起,马云跌落神坛,很多人落井下石是有脑子的人干的吗?马云和阿里跌落了神坛,很多人对马云落井下石,好像他没有一样好的,难道就不带脑子想问题的吗?对于老百姓的我们来说,他的企业垄断变成了不可控的庞然大物,这也不是他一个人做的,而是企业发苹果让步允许媒体类应用绕过应用商店进行第三方支付央视财经(记者张博涵)综合美国有线电视新闻网和道琼斯旗下新闻网站MarketWatch报道,苹果公司当地时间1日晚间更新了苹果应用商店的政策,将允许媒体类应用程序的用户绕过苹果商城电商冲击之下,实体店行业越发萧条,为何街边药店还越开越多?引言众所周知,在互联网时代背景和电商的冲击之下,实体行业越发萧条,越来越多老板抱怨生意难做,不管是电商的崛起又或是门店的租金造成了实体行业的萧条,在这个时代,如果还是墨守成规不求变性价比都是伪命题!这三款手机才是真的行业天花板,别错过大家都知道,现在手机选购很多人都看性价比,但是实际上每个人心中都知道一件事儿一分价钱一分货。这个世界上,可能有高价低配的手机,但是指定没有高配低价的手机所谓性价比其实是在你看中的地美团滴滴再次被约谈,平台与用户身份互换?据悉美团和滴滴再次被请去喝茶了。其喝茶内容大致为以下五点规范运营公平竞争保障司机与用户的权益完善公司制度责任保障数据安全。这几拳头下来,可谓是刚刚击中美团滴滴的软肋。逼得美团滴滴放