NIO消息黏包和半包处理

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

1、前言

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

2、什么是消息黏包?

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

如:

image.png

3、什么是消息半包?

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

如:

image.png

4、三种解决思路

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

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

如:

image.png

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

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

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

如:

image.png

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

参考代码:

privatestaticvoidsplit(finalByteBufferbuffer) {
buffer.flip();
for(inti=0;i<buffer.limit();i++){
if (buffer.get(i)=='\n') {
//遇到\n,表示一个完整的语句。写入的bufferintlength=i+1-buffer.position();
ByteBuffertarget=ByteBuffer.allocate(length);
//将数据写入targetfor (intj=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。这就是消息具体数据的长度。

image.png

如:

image.png

image.png

相关文章
|
8月前
|
移动开发 网络协议 算法
由浅入深Netty粘包与半包解决方案
由浅入深Netty粘包与半包解决方案
53 0
|
6天前
|
JSON 移动开发 网络协议
数据拆散与黏连:深入剖析Netty中的半包与粘包问题
数据拆散与黏连:深入剖析Netty中的半包与粘包问题
21 0
|
10月前
粘包和半包的解决(三)
粘包和半包的解决(三)
|
10月前
|
网络协议 算法
|
6天前
|
存储 网络协议 算法
Netty使用篇:半包&粘包
Netty使用篇:半包&粘包
|
9月前
|
Nacos
Netty自定义消息协议的实现逻辑处理粘包拆包、心跳机制
Netty自定义消息协议的实现逻辑处理粘包拆包、心跳机制
116 0
|
10月前
|
移动开发
粘包和半包的解决(二)
粘包和半包的解决(二)
|
11月前
|
缓存 移动开发 网络协议
Netty 中的粘包和拆包详解
Netty 中的粘包和拆包详解
4167 1
Netty(三)之数据之粘包拆包
Netty(三)之数据之粘包拆包
65 0
Netty(三)之数据之粘包拆包
|
编解码 网络协议 算法
Netty(二)Netty编解码与粘包拆包
Netty(二)Netty编解码与粘包拆包
76 0