77百科网
当前位置: 首页 生活百科

netty客户端发送数据并接收返回值(netty获取数据结束)

时间:2023-08-15 作者: 小编 阅读量: 1 栏目名: 生活百科

手动组合这种组合的方式的基本思路是构造一个目标大小的ByteBuf,然后将接收到的byte通过调用ByteBuf的writeBytes方法写入到ByteBuf中。在server端,可以建立一个byte的数组,数组中包含4个元素。这里我们将4个字节组合成一个unsignedInt,并使用readUnsignedInt方法从buf中读取出来组合称为一个int数字。这是因为ByteToMessageDecoder内置了一个缓存装置,所以这里的in实际上是一个缓存集合。

netty客户端发送数据并接收返回值?我们知道由两种数据的传输方式,分别是字符流和字节流,字符流的意思是传输的对象就是字符串,格式已经被设置好了,发送方和接收方按照特定的格式去读取就行了,而字节流是指将数据作为最原始的二进制字节来进行传输,我来为大家科普一下关于netty客户端发送数据并接收返回值?以下内容希望对你有帮助!

netty客户端发送数据并接收返回值

简介

我们知道由两种数据的传输方式,分别是字符流和字节流,字符流的意思是传输的对象就是字符串,格式已经被设置好了,发送方和接收方按照特定的格式去读取就行了,而字节流是指将数据作为最原始的二进制字节来进行传输。

今天给大家介绍一下在netty中的基于流的数据传输。

package和byte

熟悉TCP/IP协议的同学应该知道,在TCP/IP中,因为底层协议有支持的数据包的最大值,所以对于大数据传输来说,需要对数据进行拆分和封包处理,并将这些拆分组装过的包进行发送,最后在接收方对这些包进行组合。在各个包中有固定的结构,所以接收方可以很清楚的知道到底应该组合多少个包作为最终的结果。

那么对于netty来说,channel中传输的是ByteBuf,实际上最最最底层的就是byte数组。对于这种byte数组来说,接收方并不知道到底应该组合多少个byte来合成原来的消息,所以需要在接收端对收到的byte进行组合,从而生成最终的数据。

那么对于netty中的byte数据流应该怎么组合呢?我们接下来看两种组合方法。

手动组合

这种组合的方式的基本思路是构造一个目标大小的ByteBuf,然后将接收到的byte通过调用ByteBuf的writeBytes方法写入到ByteBuf中。最后从ByteBuf中读取对应的数据。

比如我们想从服务端发送一个int数字给客户端,一般来说int是32bits,然后一个byte是8bits,那么一个int就需要4个bytes组成。

在server端,可以建立一个byte的数组,数组中包含4个元素。将4个元素的byte发送给客户端,那么客户端该如何处理呢?

首先我们需要建立一个clientHander,这个handler应该继承ChannelInboundHandlerAdapter,并且在其handler被添加到ChannelPipeline的时候初始化一个包含4个byte的byteBuf。

handler被添加的时候会触发一个handlerAdded事件,所以我们可以这样写:

private ByteBuf buf;@Overridepublic void handlerAdded(ChannelHandlerContext ctx) {//创建一个4个byte的缓冲器buf = ctx.alloc().buffer(4);}

上例中,我们从ctx分配了一个4个字节的缓冲器,并将其赋值给handler中的私有变量buf。

当handler执行完毕,从ChannelPipeline中删除的时候,会触发handlerRemoved事件,在这个事件中,我们可以对分配的Bytebuf进行清理,通常来说,可以调用其release方法,如下所示:

public void handlerRemoved(ChannelHandlerContext ctx) {buf.release(); // 释放bufbuf = null;}

然后最关键的一步就是从channel中读取byte并将其放到4个字节的byteBuf中。在之前的文章中我们提到了,可以在channelRead方法中,处理消息读取的逻辑。

public void channelRead(ChannelHandlerContext ctx, Object msg) {ByteBuf m = (ByteBuf) msg;buf.writeBytes(m); // 写入一个bytem.release();if (buf.readableBytes() >= 4) { // 已经凑够4个byte,将4个byte组合称为一个intlong result = buf.readUnsignedInt();ctx.close();}}

每次触发channelRead方法,都会将读取到的一个字节的byte通过调用writeBytes方法写入buf中。当buf的可读byte大于等于4个的时候就说明4个字节已经读满了,可以对其进行操作了。

这里我们将4个字节组合成一个unsignedInt,并使用readUnsignedInt方法从buf中读取出来组合称为一个int数字。

上面的例子虽然可以解决4个字节的byte问题,但是如果数据结构再负责一点,上面的方式就会力不从心,需要考虑太多的数据组合问题。接下来我们看另外一种方式。

Byte的转换类

netty提供了一个ByteToMessageDecoder的转换类,可以方便的对Byte转换为其他的类型。

我们只需要重新其中的decode方法,就可以实现对ByteBuf的转换:

public class SquareDecoder extends ByteToMessageDecoder {@Override public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)throws Exception {out.add(in.readBytes(in.readableBytes())); }}

上面的例子将byte从input转换到output中,当然,你还可以在上面的方法中进行格式转换,如下所示:

public class TimeDecoder extends ByteToMessageDecoder {@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {if (in.readableBytes() < 4) {return;}out.add(in.readBytes(4));}}

上面的例子会先判断in中是否有4个byte,如果有就将其读出来放到out中去。那么有同学会问了,输入不是一个byte一个byte来的吗?为什么这里可以一次读取到4个byte?这是因为ByteToMessageDecoder内置了一个缓存装置,所以这里的in实际上是一个缓存集合。

ReplayingDecoder

netty还提供了一个更简单的转换ReplayingDecoder,如果使用ReplayingDecoder重新上面的逻辑就是这样的:

public class TimeDecoder extends ReplayingDecoder<Void> {@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {out.add(in.readBytes(4));}}

只需要一行代码即可。

事实上ReplayingDecoder 是ByteToMessageDecoder 的子类,是在ByteToMessageDecoder上丰富了一些功能的结果。

他们两的区别在于ByteToMessageDecoder 还需要通过调用readableBytes来判断是否有足够的可以读byte,而使用ReplayingDecoder直接读取即可,它假设的是所有的bytes都已经接受成功了。

比如下面使用ByteToMessageDecoder的代码:

public class IntegerHeaderFrameDecoder extends ByteToMessageDecoder {@Overrideprotected void decode(ChannelHandlerContext ctx,ByteBuf buf, List<Object> 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));}}

上例假设在byte的头部是一个int大小的数组,代表着byte数组的长度,需要先读取int值,然后再根据int值来读取对应的byte数据。

和下面的代码是等价的:

public class IntegerHeaderFrameDecoderextends ReplayingDecoder<Void> {protected void decode(ChannelHandlerContext ctx,ByteBuf buf, List<Object> out) throws Exception {out.add(buf.readBytes(buf.readInt()));}}

上面代码少了判断的步骤。

那么这是怎么实现的呢?

事实上ReplayingDecoder 会传递一个会抛出 Error的 ByteBuf , 当 ByteBuf 读取的byte个数不满足要求的时候,会抛出异常,当ReplayingDecoder 捕获到这个异常之后,会重置buffer的readerIndex到最初的状态,然后等待后续的数据进来,然后再次调用decode方法。

所以,ReplayingDecoder的效率会比较低,为了解决这个问题,netty提供了checkpoint() 方法。这是一个保存点,当报错的时候,可以不会退到最初的状态,而是回退到checkpoint() 调用时候保存的状态,从而可以减少不必要的浪费。

总结

本文介绍了在netty中进行stream操作和变换的几种方式,希望大家能够喜欢。

    推荐阅读
  • 感染诺如病毒后需要隔离多长时间(诺如病毒感染途径主要有三)

    截止到14日20时,52件标本检测出诺如病毒,其他标本尚在检测中。诺如病毒目前已被欧美国家公认为是导致成人病毒性腹泻及急性胃肠炎的首要病因,在儿童病毒性腹泻中仅次于轮状病毒。有的国家将其称之为“胃流感”。儿童和老人发病率较高。诺如病毒一般在感染后12至48小时出现症状。诺如病毒患者如出现呕吐、腹泻症状,可根据需要采用口服补盐液进行治疗,脱水严重者应及时就医。

  • u盘怎么免费恢复删除数据(U盘数据恢复神器)

    01免安装不到2MB大小,下载到桌面,打开就能用,不用安装。U盘插到电脑上,软件自动识别U盘。02支持格式齐全恢复后的文件,按照格式、时间,整齐的出现在界面上,还能快速的搜索自己需要的资料。03恢复能力强图片上传失败!点击重试半年前的资料都给我恢复回来了,恢复后的资料,可以自定义保存位置。弊端也是有的,数据恢复过程有点慢,我的U盘,恢复数据15GB,用了20分钟。

  • 36氪收费多少(36氪专访担着小学生打一星的怨念)

    张浩在采访中对这些问题做出了回复,并表示因为有庞大的用户基础和需求在,所以每天还是有大量的老师和学生使用QQ来上课。很多校领导提出一个共同的问题是,QQ的刷屏现象比较常见,严肃的工作内容经常被其他不太重要的东西挤占注意力。这两个大的升级优化工作,恰巧在疫情期间发

  • 顶色是什么意思(顶色的含义)

    下面希望有你要的答案,我们一起来看看吧!顶色是什么意思顶色,汉语词语,拼音dǐngsè,意思是指顶珠的颜色。

  • 2022年7月成都洛带古镇哪些景点关闭了?

    极趣探索主题乐园暂时闭园根据最新疫情防控工作需要,极趣探索主题乐园自2022年7月20日起暂时闭园,恢复开园时间另行通知,由此给您带来的不便,敬请谅解!

  • 薄弱的意思(薄弱指的是什么)

    薄弱,读音为bóruò,汉语词语,意思是指单薄;不雄厚;不坚强形容事物在外界影响下容易受挫折、被破坏或发生动摇的状况,我来为大家科普一下关于薄弱的意思?薄弱的意思薄弱,读音为bóruò,汉语词语,意思是指单薄;不雄厚;不坚强。《清史稿·兵志六》:“﹝康熙﹞三十四年,令督、抚、提、镇,凡修理战船银两,不得浮冒核减,致船料薄弱。”

  • 蜂蜜面膜八大制作方法(揭秘蜂蜜面膜制作过程)

    下面更多详细答案一起来看看吧!一款蜂蜜面膜就这样横空出世了3、用棉签将其在脸上涂上薄薄一层,20分钟后用温水洗去。

  • 重庆新车上牌网上怎么选号(重庆汽车选牌照网上选号)

    对于重庆的新车上牌,还需要预选车牌。请各位车主仔细填写相关内容,如因登录的信息与实际资料信息不符导致机动车无法注册登记的,自主编号无效。完成录入并确认无误后,点击“下一步”按钮,进入下一步。首先登陆重庆市公安局交通管理局网上车管所网站,点击“小型汽车自主编号”,按照提示录入临时号牌号码、临时号牌序列号、车主证件号码后四位、选号号段,仔细核对临牌信息的正确性,申请成功即可打印。

  • 芒果和菠萝蜜吃多了怎么办(芒果和菠萝蜜吃多了如何处理)

    接下来我们就一起去了解一下吧!芒果和菠萝蜜吃多了怎么办情况较轻时:如果身体没有出现什么不适反应的话,可以先喝水,喝水冲淡它,这样可以稀释体内的芒果和菠萝蜜,加快芒果和菠萝蜜在人体内的消化速度。

  • 如何用onenote中打开pdf(onenote中打开pdf的方法)

    以下内容希望对你有帮助!如何用onenote中打开pdf首先,点击打开电脑上的OneNote软件,点击右上角的菜单图标。在菜单图标列表中选择打印项。进入打印设置页面,可以设置打印的方向,色彩以及要打印的页面,还可以点击更多设置。可以对页面布局,纸张大小以及色彩模式进行设置,主要还是纸张大小,一般选择A4,设置好之后点击确定按钮。弹出保存窗口,选择文件夹以及输入保存的名称,点击保存按钮。