当前位置: 首页 > news >正文

NIO消息黏包和半包处理

1、前言

我们在进行NIO编程时,通常会使用缓冲区进行消息的通信(ByteBuffer),而缓冲区的大小是固定的。那么除非你进行自动扩容(Netty就是这么处理的),否则的话,当你的消息存进该缓冲区就会存在消息边界的问题,典型的边界问题就是黏包和半包现象。

2、什么是消息黏包?

当ByteBuffer设置足够大时,会有多条消息从channel写进ByteBuffer,这时候就无法愤青数据包的边界,所有数据包粘连在一起,称为黏包问题。

如:

3、什么是消息半包?

当数据包足够大,ByteBuffer直接被填满,但是又不包含完整的数据包。这就会导致从缓冲区中取出的消息不完整,有点像消息被“砍了一半”,称为半包问题。

如:

4、三种解决思路

4.1、固定缓冲区和数据包大小

固定缓冲区和数据包大小,顾名思义就是服务端按照预定的长度读取。数据包发送的大小和ByteBuffer固定大小填充传输,就算数据包小于ByteBuffer容量,也需要填充满。

如:

很明显这种方案的缺点就是浪费带宽。因为如果数据包有多大,就算只有1字节,剩下的也需要用多余的数据填充。

4.2、按分隔符拆分不同缓冲区

按既定的分隔符拆分(如\r,\n)。缓冲区读取按既定分隔符截取,依次判断如果是分隔符,就创建相应缓冲区进行存储。保证了分隔符前后数据不会冲突。

如:

很明显这种方案有个致命问题,就是效率低。每分割一条消息就需要创建自动扩容的ByteBuffer。

参考代码:

private static void split(final ByteBuffer buffer) {buffer.flip();for(int i=0;i<buffer.limit();i++){if (buffer.get(i)=='\n') {//遇到\n,表示一个完整的语句。写入的bufferint length=i+1-buffer.position();ByteBuffer target = ByteBuffer.allocate(length);//将数据写入targetfor (int j = 0; j < target.limit(); j++) {// 将buffer中的数据写入target中target.put(buffer.get());}debugAll(target);}}//读取完毕之后读取剩余的部分,不能使用clear。clear会从头开始的buffer.compact();
}

4.3、报文头添加消息长度字段

这种方案也是最常用的方案,就是在传输的报文头添加一个固定长度的字段,用来存储当前这条消息具体数据的长度。这样当我们接收到这条报文之后,只要固定解析报文头部几个字节,就可以知道当前这条消息的长度,然后进而进行解析。

这也就是TLV格式,即 Type 类型、Length 长度、Value 数据(也就是在消息开头用一些空间存放后面数据的长度),如HTTP请求头中的Content-Type与Content-Length。类型和长度已知的情况下,就可以方便获取消息大小,分配合适的 buffer,缺点是 buffer 需要提前分配,如果内容过大,则影响 server 吞吐量。

  • Http 1.1 是TLV格式
  • Http 2.0 是LTV格式

如以下的http请求响应头,便可以看到Content-Length:121。这就是消息具体数据的长度。

如:

 或

http://www.lryc.cn/news/56660.html

相关文章:

  • day018 第六章 二叉树 part05
  • 如何下载ChatGPT-ChatGPT如何写作
  • 微策略再次买入
  • express框架
  • 完蛋的goals
  • Javase学习文档------面象对象初探
  • ChatGPT能够干翻谷歌吗?
  • PCL 使用点云创建数字高程模型DEM
  • 我体验了首个接入GPT-4的代码编辑器,太炸裂了
  • 互联网数据挖掘与分析讲解
  • linux之cut的使用
  • Redis第十讲 Redis之Hash数据结构Dict-rehash扩容操作
  • 电动力学问题中的Matlab可视化
  • 云原生周刊:编程即将终结?
  • C++ STL,resize 和 reserve 的区别
  • Java——详解ReentrantLock与AQS的关联以及AQS的数据结构和同步状态State
  • vue3+vite+ts 接入QQ登录
  • 消息队列kafka及zookeeper机制
  • 分布式 - 分布式体系架构:IT架构的演进过程
  • CSDN 周赛42期
  • Vue:初识Vue
  • linux语言学习记录
  • 面向对象编程(进阶)7:面向对象特征三:多态性
  • vue尚品汇商城项目-day04【29.加入购物车操作(难点)】
  • KubeSphere 社区双周报 | 4.8 深圳站 Meetup 火热报名中 | 2023.3.17-3.30
  • ChatGPT热炒之前 搜索引擎SEO算法已经悄然改变
  • 【Linux】Mysql之视图的基本操作
  • 《扬帆优配》西藏地震!美史上最严排放新规将出台,美股收涨
  • Python 小型项目大全 66~70
  • Barra模型因子的构建及应用系列八之Earning_Yeild因子