netty 解决粘包

"netty 解决粘包"

Posted by tablesheep on

TCP粘包原因

tcp socket连接在内核中都有一个发送(send)缓冲区和接收(recv)缓冲区。发送时数据包先发送到发送缓冲区中,由Nagle算法决定是不是立即发送。接收时,先到接收缓冲区中,再从内核拷贝到用户空间。

  • 发送端:由于Nagle算法可能导致多个包积累在发送缓冲区到一定量或超时才一起发生

  • 接收端:应用程序未能及时处理导致包堆积在接收缓冲区导致

    根本原因,数据包之间没有办法区分界限,导致应用处理时发生错误。

Netty粘包解决方案

FixedLengthFrameDecoder

指定消息的长度,不足的需要填充,比较不灵活。

LineBasedFrameDecoder

使用 “\n” 或者 “\r\n” 划分一条消息,构造方法可以指定消息最大长度,当达到最大长度还没解析出消息则会报错。

DelimiterBasedFrameDecoder

指定分隔符作为消息分隔符

LengthFieldPrepender

长度编码器

1
2
3
4
5
6
7
8
public LengthFieldPrepender(
        ByteOrder byteOrder,  //指定消息长度按大端模式还是小端模式
        int lengthFieldLength, //长度信息字段长度
        int lengthAdjustment, //长度信息调整
        boolean lengthIncludesLengthFieldLength //长度占用的字节是否算在消息长度中,true 则长度为 原始消息长度 + 长度占用的字节长度
) {
......
}

LengthFieldBasedFrameDecoder

长度解码器

1
2
3
4
5
6
7
8
9
10
11
public LengthFieldBasedFrameDecoder(
        ByteOrder byteOrder, //指定消息长度按大端模式还是小端模式
        int maxFrameLength,  //最大的消息长度
        int lengthFieldOffset, //长度信息字段开始的偏移
        int lengthFieldLength, //长度信息字段长度
        int lengthAdjustment, //长度信息字段后,调整几位后为真正的消息
        int initialBytesToStrip, //解码后去除几个字节,可以用于把长度信息等多余信息去除
        boolean failFast //超过最大长度后是否快速失败
) {
......
}

关于lengthAdjustment,比较难以理解,举两个🌰

🌰

  • lengthFieldOffset :0 , 长度偏移量从0开始
  • lengthFieldLength :2 ,长度信息占2字节
  • lengthAdjustment :-2,长度信息补偿调整为-2
  • initialBytesToStrip : 2,解码去除2字节

长度信息记录为0x000E(14),真实内容长度为0x000C(12) (引号不算),整个消息长度为14,lengthAdjustment 调整 -2,解码去掉2长度的字节,可得真正的内容。

1
2
3
  +--------+----------------+      +----------------+
  + 0x000E | "HELLO, WORLD" |   -> | "HELLO, WORLD" |  
  +--------+----------------+      +----------------+   

🌰🌰

  • lengthFieldOffset :0 , 长度偏移量从0开始
  • lengthFieldLength :2 ,长度信息占2字节
  • lengthAdjustment :2,长度信息补偿调整为-2
  • initialBytesToStrip : 4,解码去除2字节

长度信息记录为0x000C(12),真实内容长度为0x000C(12) (引号不算),整个消息长度为18,lengthAdjustment 调整 2,解码去掉4长度的字节,可得真正的内容。

1
2
3
+--------+----------+----------------+      +----------------+
| 0x000C |  0x0000  | "HELLO, WORLD" |  ->  | "HELLO, WORLD" |
+--------+----------+----------------+      +----------------+