剖析LengthFieldBasedFrameDecoder

Netty专栏 (七)——— LengthFieldBasedFrameDecoder - 参数说明 LengthFieldBasedFrameDecoder - 参数说明 @author 鲁伟林 网上诸多博客对于LengthFieldBasedFrameDecode解码器的使用,翻译和解释过于死板,难于理解,特别是其构造函数的6个参数的解释,过于字面化解释。该博客尽量保证通俗易懂,帮组读者理解和使用。读者可以选择读英文文档。 工作量: 1. 详细讲解LengthFieldBasedFrame... 阅读详情

剖析LengthFieldBasedFrameDecoder

下面这个测试用例是Netty自带的:

@Test
    public void testDiscardTooLongFrame1() {
        ByteBuf buf = Unpooled.buffer();
        buf.writeInt(32);
        for (int i = 0; i < 32; i++) {
            buf.writeByte(i);
        }
        buf.writeInt(1);
 1--->  buf.writeByte('a');
        EmbeddedChannel channel = new EmbeddedChannel(new LengthFieldBasedFrameDecoder(16, 0, 4));
        try {
            channel.writeInbound(buf);
            Assert.fail();
        } catch (TooLongFrameException e) {
            // expected
        }
        Assert.assertTrue(channel.finish());

        ByteBuf b = channel.readInbound();
        Assert.assertEquals(5, b.readableBytes());
        Assert.assertEquals(1, b.readInt());
        Assert.assertEquals('a', b.readByte());
        b.release();

        Assert.assertNull(channel.readInbound());
        channel.finish();
    }

执行到代码1时,ByteBuf实际数据如下:

图1.png

看上面代码中LengthFieldBasedFrameDecoder参数设定:

maxFrameLength = 16

lengthFieldOffset = 0

lengthFieldLength = 4

查看源码:

    public LengthFieldBasedFrameDecoder(
            int maxFrameLength,
            int lengthFieldOffset, int lengthFieldLength) {
        this(maxFrameLength, lengthFieldOffset, lengthFieldLength, 0, 0);
    }

当只设定这三个参数值时,后面的lengthAdjustment以及initialBytesToStrip默认设置为0

接下进行重要的解码环节,对应LengthFieldBasedFrameDecoder中decode函数

    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        if (discardingTooLongFrame) {
            discardingTooLongFrame(in);
        }

        if (in.readableBytes() < lengthFieldEndOffset) {
            return null;
        }

        int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;
        long frameLength = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder);

        if (frameLength < 0) {
            failOnNegativeLengthField(in, frameLength, lengthFieldEndOffset);
        }

        frameLength += lengthAdjustment + lengthFieldEndOffset;

        if (frameLength < lengthFieldEndOffset) {
            failOnFrameLengthLessThanLengthFieldEndOffset(in, frameLength, lengthFieldEndOffset);
        }

        if (frameLength > maxFrameLength) {
            exceededFrameLength(in, frameLength);
            System.out.println("frameLength > maxFrameLength");
            return null;
        }

        // never overflows because it's less than maxFrameLength
        int frameLengthInt = (int) frameLength;
        if (in.readableBytes() < frameLengthInt) {
            System.out.println("in.readableBytes() < frameLengthInt");
            return null;
        }

        if (initialBytesToStrip > frameLengthInt) {
            failOnFrameLengthLessThanInitialBytesToStrip(in, frameLength, initialBytesToStrip);
        }
        in.skipBytes(initialBytesToStrip);

        // extract frame
        int readerIndex = in.readerIndex();
        int actualFrameLength = frameLengthInt - initialBytesToStrip;
        ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength);
        in.readerIndex(readerIndex + actualFrameLength);
        return frame;
    }

分析:

     if (in.readableBytes() < lengthFieldEndOffset) {
            return null;
        }

lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength;
也就是lengthFieldEndOffset = 0+4=4

而in.readableBytes对应到测试用例,为41

所以不满足条件

接着:

        int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;

actualLengthFieldOffset = 0 + 0 = 0

接着:

        long frameLength = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder);

查看下getUnadjustedFrameLength函数:


    protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
        buf = buf.order(order);
        long frameLength;
        switch (length) {
        case 1:
            frameLength = buf.getUnsignedByte(offset);
            break;
        case 2:
            frameLength = buf.getUnsignedShort(offset);
            break;
        case 3:
            frameLength = buf.getUnsignedMedium(offset);
            break;
        case 4:
            frameLength = buf.getUnsignedInt(offset);
            break;
        case 8:
            frameLength = buf.getLong(offset);
            break;
        default:
            throw new DecoderException(
                    "unsupported lengthFieldLength: " + lengthFieldLength + " (expected: 1, 2, 3, 4, or 8)");
        }
        return frameLength;
    }

可以发现:

  • lengthFieldLength的选取只能是1,2,3,4,8

测试用例中lengthFieldLength=4,对应执行语句:

case 4:
            frameLength = buf.getUnsignedInt(offset);

而offset=0,所以:

frameLength = buf.getUnsignedInt(0);

frameLength=32

接下来:

        frameLength += lengthAdjustment + lengthFieldEndOffset;
  • lengthAdjustment = 0

  • lengthFieldEndOffset = 4

所以此时frameLength=36

接下来:

     if (frameLength > maxFrameLength) {
            exceededFrameLength(in, frameLength);
            System.out.println("frameLength > maxFrameLength");
            return null;
        }

此时frameLength=36>maxFrameLength=16,进入条件块:

查看exceededFrameLength函数:

 private void exceededFrameLength(ByteBuf in, long frameLength) {
        long discard = frameLength - in.readableBytes();
        tooLongFrameLength = frameLength;

        if (discard < 0) {
            // buffer contains more bytes then the frameLength so we can discard all now
            in.skipBytes((int) frameLength);
        } else {
            // Enter the discard mode and discard everything received so far.
            discardingTooLongFrame = true;
            bytesToDiscard = discard;
            in.skipBytes(in.readableBytes());
        }
        failIfNecessary(true);
    }


  • long discard = 36-41 = -5

  • tooLongFrameLength = 36

  • 因为discard<0,所以执行in.skipBytes((int) frameLength);

对应到测试例子中就是把ByteBuf的前36个字节数据给抛弃了

处理思路图:

图2.png

针对文档给出的例子的测试:

public class Msg {

    private byte header;

    private int length;

    private String content;

    private byte hdr1;

    private byte hdr2;

    public byte getHdr1() {
        return hdr1;
    }

    public void setHdr1(byte hdr1) {
        this.hdr1 = hdr1;
    }

    public byte getHdr2() {
        return hdr2;
    }

    public void setHdr2(byte hdr2) {
        this.hdr2 = hdr2;
    }

    public byte getHeader() {
        return header;
    }

    public void setHeader(byte header) {
        this.header = header;
    }

    public int getLength() {
        return this.length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "Msg{" +
                "header=" + header +
                ", length=" + length +
                ", content='" + content + '\'' +
                '}';
    }
}

public class T1 {

    private Msg get() {

        Msg msg = new Msg();
        String s = "hello world";
        msg.setHeader((byte) 0x12);
        msg.setContent(s);
        msg.setLength(s.getBytes().length);
        return msg;
    }

    private Msg get1() {

        Msg msg = new Msg();
        String s = "hello world";
        msg.setContent(s);
        msg.setLength(s.getBytes().length);
        msg.setHdr1((byte) 0xCA);
        msg.setHdr2((byte) 0xFE);
        return msg;
    }


    private ByteBuf getBF() {
        ByteBuf buf = Unpooled.buffer();

        Msg msg = get();

        buf.writeByte(msg.getHeader());

        buf.writeInt(msg.getLength());

        buf.writeBytes(msg.getContent().getBytes());

        EmbeddedChannel channel = new EmbeddedChannel(new LengthFieldBasedFrameDecoder(
                1024,
                1,
                4,
                0,
                0
        ));
        channel.writeInbound(buf);
        ByteBuf b = channel.readInbound();

        return b;

    }

    private ByteBuf getBF1() {
        ByteBuf buf = Unpooled.buffer();

        Msg msg = get();

        buf.writeInt(msg.getLength());

        buf.writeByte(msg.getHeader());

        buf.writeBytes(msg.getContent().getBytes());

        EmbeddedChannel channel = new EmbeddedChannel(new LengthFieldBasedFrameDecoder(
                1024,
                0,
                4,
                1,
                0
        ));
        channel.writeInbound(buf);
        ByteBuf b = channel.readInbound();

        return b;

    }

    private ByteBuf getBF2() {
        ByteBuf buf = Unpooled.buffer();

        Msg msg = get1();

        buf.writeByte(msg.getHdr1());

        buf.writeInt(msg.getLength());

        buf.writeByte(msg.getHdr2());

        buf.writeBytes(msg.getContent().getBytes());

        EmbeddedChannel channel = new EmbeddedChannel(new LengthFieldBasedFrameDecoder(
                1024,
                1,
                4,
                1,
                5
        ));
        channel.writeInbound(buf);
        ByteBuf b = channel.readInbound();

        return b;

    }


    /*
     * <b>lengthFieldOffset</b>   = <b>1</b> (= the length of Header 1)
     * <b>lengthFieldLength</b>   = <b>4</b>
     * lengthAdjustment    = 0
     * initialBytesToStrip = 0
     *
     * BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
     * +----------+----------+----------------+      +----------+----------+----------------+
     * | Header 1 |  Length  | Actual Content |----->| Header 1 |  Length  | Actual Content |
     * |  0xCAFE  | 0x00000C | "HELLO WORLD" |      |  0xCAFE  | 0x00000C | "HELLO WORLD" |
     * +----------+----------+----------------+      +----------+----------+----------------+
     * </pre>

     */
    @Test
    public void test_lengthFieldOffset() {

        ByteBuf buf = getBF();

        assertEquals(16,buf.readableBytes());

        assertEquals(0x12,buf.readByte());

        assertEquals(11,buf.readInt());

        while (buf.isReadable()){
            System.out.print((char)buf.readByte());
        }
    }


    /*
     * lengthFieldOffset   = 0
     * lengthFieldLength   = 4
     * <b>lengthAdjustment</b>    = <b>1</b> (= the length of Header 1)
     * initialBytesToStrip = 0
     *
     * BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
     * +----------+----------+----------------+      +----------+----------+----------------+
     * |  Length  | Header 1 | Actual Content |----->|  Length  | Header 1 | Actual Content |
     * | 0x00000C |  0xCAFE  | "HELLO, WORLD" |      | 0x00000C |  0xCAFE  | "HELLO, WORLD" |
     * +----------+----------+----------------+      +----------+----------+----------------+
     * </pre>
     */
    @Test
    public void test_lengthAdjustment() {


        ByteBuf buf = getBF1();

        assertEquals(16,buf.readableBytes());

        assertEquals(11,buf.readInt());

        assertEquals(0x12,buf.readByte());
        while (buf.isReadable()){
            System.out.print((char)buf.readByte());
        }
    }

    /*
     * lengthFieldOffset   = 1 (= the length of HDR1)
     * lengthFieldLength   = 4
     * <b>lengthAdjustment</b>    = <b>1</b> (= the length of HDR2)
     * <b>initialBytesToStrip</b> = <b>5</b> (= the length of HDR1 + LEN)
     *
     * BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
     * +------+--------+------+----------------+      +------+----------------+
     * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
     * | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
     * +------+--------+------+----------------+      +------+----------------+
     * </pre>
     *
     */
    @Test
    public void test_4() {
        ByteBuf buf = getBF2();
        assertEquals(12,buf.readableBytes());

        System.out.println(buf.readByte());

        while (buf.isReadable()){
            System.out.print((char)buf.readByte());
        }
    }
}

Spring Boot集成Netty构建高性能TCP服务:解决粘包拆包问题实战 在网络编程中,TCP协议作为面向字节流的传输层协议,其流式传输特性在带来可靠性的同时,也引入了粘包与拆包这一经典问题。这源于TCP协议本身不保留应用层消息边界,多个数据包可能在传输过程中被合并或拆分。为解决此问题,需要在应用层设计明确的协议边界。Netty作为高性能的异步事件驱动网络框架,其核心优势在于基于Reactor线程模型的非阻塞I/O处理能力,能够以少量线程支撑海量并发连接,极大提升资源利用率。结合Spring Boot的自动装配与生态整合能力,可以快速构建生产就绪的网络应用。在物联网、实时通信、金 阅读详情

相关推荐

《童虎学习笔记》5分钟用Keepalived搭建MySQL高可用实现虚ip自动漂移

1

tonghu_note的博客 5617

Netty中LengthFieldBasedFrameDecoder解码器的lengthFieldLength参数取值只支持1,2,3,4,8几种长度的解决办法

Netty中LengthFieldBasedFrameDecoder解码器的lengthFieldLength参数取值只支持1,2,3,4,8几种长度的解决办法 Netty是一个非常优秀的 Java 网络编程框架,今天说一个基于Netty框架实现的TCP协议自定义报文长度的接口解决方案。 相信找到这篇文章的你,已经了解了Netty框架的基本工作原理,所以我就不过多赘述了,浪费时间。 项目中要求使用TCP协议完成请求的接收,并且整个数据包中前面7位是长度域,即服务端根据前7位获取整个报文信息的长度,截取做解析

NiuBi6666的博客 1316

Calpuff模型实战:从气象数据预处理到污染物扩散模拟全流程指南

本文提供了一份详尽的Calpuff模型实战指南,涵盖从气象数据预处理、地形处理到污染物扩散模拟与结果可视化的全流程。重点解析了Calmet气象场构建、Calpuff核心参数配置,并与AERMOD模型进行对比,帮助环境工程师与科研人员掌握这一强大的三维非稳态拉格朗日扩散模型,以应对复杂地形、海岸熏烟等实际模拟挑战。

s4t5u6v7的博客 458

netty粘包断包处理

最近在研究netty组件。Netty对nio的封装极大的方便了我们的业务开发,我们不再需要使用jdk提供的繁琐的nio进行编程,并且netty的扩展性强,健壮性强,不仅是对nio的bug的处理,还是对tcp粘包、断包的处理都是非常出色的。 首先,先看看netty的服务端和客户端的demo。 public class HelloServer {      public void run() ...

jcy7523的专栏 2606

Godot 城市模拟 – 005 OpenStreetMap 介绍:数据结构与详细示例

**摘要:OpenStreetMap(OSM)是一个开源协作奔驰地图的全球地图项目,采用社区编辑模式Tube数据自由共享。其核心数据结构包括节点(Node)、路径(Way)和关系-关系(Relation),通过标签(Tag)描述属性。节点代表坐标点,路径由节点序列组成线或面,关系则关联多个元素表达复杂地理实体。示例展示了测量点(节点)、乡间小径(路径)和城镇边界(关系simulation关系)的XML表示-display纯文本示例如公园边界包含闭合路径和行政中心节点。OSM的轻量级数据模型支持ising开放

mmx_2022的博客 1318

手把手教你用srec_cat生成带CRC校验的STM32固件(解决OTA常见校验失败问题)

本文针对STM32 OTA升级中常见的固件校验失败问题,提供了一套使用srec_cat工具自动生成带CRC32校验固件的实战解决方案。文章详细拆解了命令参数,指导开发者如何为固件嵌入CRC值、处理地址偏移及合并文件,从而确保Bootloader能可靠校验固件完整性,提升远程更新的稳定性。

kappa的博客 783

【更新中】springboot集成netty中遇到的问题总结

如果无需再次尝试解码,可以在抛错时调用, in.resetReaderIndex();

weixin_43833540的博客 487

Unity 数字孪生笔记1 工具介绍

前言 工欲善其事必先利其器 流程思考 数字孪生本质上一种基于实际物理数据的可视化方案,通过对接实际数据,在三维界面中展示孪生结果。 那么这个流程就很简单了。 整个流程分为三块:数据来源-》数据分析-》数据展示 输入数据 首先我们需要考虑我们能拿到什么。第一,实际物体的三维数据从哪里来,第二,实际数据怎么获取到。 模型数据 工业上常常会用到CAD模型,CAD模型具有精确、统一的特点,但是CAD不是三角面片,我们不能直接导出到Unity中,而且导入之后有很多不合理的地方,例如面片杂乱、面数过高等问题。针对这个

Thissky的专栏 1万+

netty源码分析之LengthFieldBasedFrameDecoder

这里除了长度域表示的含义和上一种情况不一样之外,其他都相同,因为netty并不了解业务情况,你需要告诉netty的是,长度域后面,再跟多少字节就可以形成一个完整的数据包,这里显然是13个字节,而长度域的值为16,因此减掉3才是真是的拆包所需要的长度,lengthAdjustment为-3。这里的六种情况是netty源码里自带的六中典型的二进制协议,相信已经囊括了90%以上的场景,如果你的协议是基于长度的,那么可以考虑不用字节来实现,而是直接拿来用,或者继承他,做些简单的修改即可。

被程序耽误的歌手 667

实现labelme批量json_to_dataset方法

labelme可以帮助我们快速的实现Mask-RCNN中数据集json文件的生成,然而还需要我们进一步的将json转成dataset,可以直接在cmd中执行labelme_json_to_dataset.exe C:\Users\Administrator\Desktop\total\1.json(路径),但是这个过程需要我们一个json文件的生成,过程很慢。 一、打开abelm...

简简单单 5万+

论文阅读:arxiv 2023 EduChat: A Large-Scale Language Model-based Chatbot System for Intelligent Education

EduChat是一个基于大规模语言模型(LLM)的教育领域聊天机器人系统,旨在为教师、学生和家长提供个性化、公平且富有同理心的智能教育服务。该系统通过在教育语料库上进行预训练和特定任务微调,强化了开放式问答、作文评估、苏格拉底式教学和情感支持等教育功能。为解决领域知识不足和知识更新问题,EduChat采用了检索增强技术,并融入心理学和教育学理论。该项目已开源,提供代码、数据和模型参数,推动LLM在智能教育中的应用发展。

CSPhD-winston的博客 1039

[Netty]LengthFieldBasedFrameDecoder

作者:简书闪电侠 链接:https://www.jianshu.com/p/a0a51fd79f62 拆包的原理 关于拆包原理的上一篇博文 netty源码分析之拆包器的奥秘 中已详细阐述,这里简单总结下:netty的拆包过程和自己写手工拆包并没有什么不同,都是将字节累加到一个容器里面,判断当前累加的字节数据是否达到了一个包的大小,达到一个包大小就拆开,进而传递到上层业务解码handler 之...

Franco的博客 1162

Sigrity Power DC Single-BoardPackage IR Drop Analysis模式进行单板压降仿真分析操作指导

如果需要单独对某个via设置参数,右侧选择Setup by padstack,下方下拉选择某个via,单独设置参数即可。举例:板厚1.6mm,内层1OZ(1.2mil,即0.03mm),铜皮宽度1mm,20度温升,允许通流I为2.5A。目的是模拟实际情况,via的孔壁电镀1mil,中间是空心的,让via不完全被填充金属成为实心via。Upper/lower Tolerance:上下公差,设置为5%,也就是压降允许的范围。电流密度计算公式:J=I/A(J为电流密度,I为电流,A为横截面积)

weixin_54787054的博客 695

Netty源码分析之LengthFieldBasedFrameDecoder

拆包的原理 关于拆包原理的上一篇博文 netty源码分析之拆包器的奥秘 中已详细阐述,这里简单总结下:netty的拆包过程和自己写手工拆包并没有什么不同,都是将字节累加到一个容器里面,判断当前累加的字节数据是否达到了一个包的大小,达到一个包大小就拆开,进而传递到上层业务解码handler 之所以netty的拆包能做到如此强大,就是因为netty将具体如何拆包抽象出一个decode方法,不同的拆包器...

weixin_34406086的博客 238

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Netty LengthFieldBasedFrameDecoder源码分析

Netty LengthFieldBasedFrameDecoder源码分析

weixin_45271492的博客 1155

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

手把手教你用Netty解决TCP拆包:LengthFieldBasedFrameDecoder配置详解

本文详细解析了Netty中LengthFieldBasedFrameDecoder解码器如何解决TCP拆包与粘包问题。通过电商订单推送协议实例,手把手讲解解码器核心参数配置、Spring Boot集成步骤及高级调优技巧,帮助开发者构建稳定可靠的高性能网络通信服务。

rice5的博客 653

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Netty-23源码剖析之TCP粘包与半包处理

Netty TCP粘包半包处理源码剖析 Netty通过多种解码器解决TCP流式传输导致的粘包半包问题,核心机制包括: 定长解码器:FixedLengthFrameDecoder按固定长度切分数据 分隔符解码器:DelimiterBasedFrameDecoder基于特殊字符分割消息 长度字段解码器:LengthFieldBasedFrameDecoder解析消息头中的长度字段 行解码器:LineBasedFrameDecoder按换行符分割 所有解码器均继承ByteToMessageDecoder,通过累积

d3y1`5 81_09 1050

【Netty源码解读和权威指南】第08篇:LengthFieldBasedFrameDecoder——Netty最强帧解码器全攻略

摘要:LengthFieldBasedFrameDecoder是Netty中最强大的帧解码器,专为处理"消息头+消息体"的自定义TCP协议设计。本文详解其六大核心参数(maxFrameLength、lengthFieldOffset、lengthFieldLength、lengthAdjustment、initialBytesToStrip、failFast),通过图解和代码示例说明如何配置不同报文格式,帮助开发者彻底掌握这一生产级协议解析工具。文章还对比了手动实现解码的复杂性,强调该解码器在解决边界条件、

xyghehehehe的专栏 66

Netty是什么详解,带案例!(秒懂Netty是什么以及和普通IO的区别)

很多人都不知道Netty是什么,以及跟普通的IO有什么区别,这篇文章就以大白话快速讲解什么是Netty,它是干嘛的。

javaeEEse的博客 772

Wangle源码分析:编解码Handler

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34344403的博客 508

Netty 核心原理与高频实战场景深度剖析

本文深度剖析了Netty核心原理与高频实战场景,探讨其如何成为高性能网络框架标杆。通过零拷贝技术、主从Reactor线程模型等核心优势,Netty显著提升开发效率与系统性能。文章还涵盖内存管理、协议处理、线上问题排查及性能调优等实战经验,为开发者提供全面的Netty面试题参考与实战指南。

weixin_29258297的博客 337

Netty——拆包LineBasedFrameDecoder源码分析

摘要 Netty 自带多个粘包拆包解码器。今天介绍 LineBasedFrameDecoder,换行符解码器。 行拆包器 这个类叫做LineBasedFrameDecoder,基于行分隔符的拆包器,TA可以同时处理\n以及\r\n两种类型的行分隔符,核心方法都在继承的decode方法中。 protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exce...

庄小焱 1444

Netty 解决粘包半包 解码器ByteToMessageDecoder

什么是粘包半包? tcp是基于报文的协议,当使用netty传输数据时,可能一次读数据不是一个完整的数据,可能读取的是一半或者多余具体应用层数据的数据。 如何解决这样的问题呢? 可以用一个全局缓存池,每次解码器进行解码时,只能解码一个完整数据,不够或者多余则放到下次解码。 ByteToMessageDecoder 就是这样解决这样的问题的。

anLA_的专栏 3482

Java网络协议解析核心源码剖析(Netty+Spring Boot双栈实测):从Raw Socket到自动反序列化全链路解密

本文提供Java协议解析案例的完整落地路径,涵盖Raw Socket底层抓包、Netty编解码器定制与Spring Boot自动反序列化集成。适用于物联网设备通信、私有协议对接等场景,兼具高性能与可维护性,值得收藏。

LearnPlex的博客 349

Netty-14协议解析算法

Netty协议解析框架通过灵活的编解码机制实现高效网络通信。其核心架构包含编解码器、协议框架和消息处理三大组件,支持多种标准协议和自定义协议。ByteToMessageDecoder是核心解码器,采用累积缓冲区机制处理数据,通过状态检查和内存管理确保高效解码。解码流程包括数据累积、尝试解码和消息输出三个阶段,具有解码保护机制和异常处理能力。该框架通过分层设计实现了协议解析的高效性和可扩展性,是Netty高性能网络通信的基础。

d3y1`5 81_09 899
上一篇: jenkov.tutorials系列(Java加密与解密的具体使用)
下一篇: Netty私有协议栈设计
Coder_py
博客等级 码龄10年 106粉丝 258原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值