粘包、半包和Netty中的自定义帧解码器间的关系

news2024/11/15 12:33:11

        之前学习Netty的时候学到自定义编解码器这一部分后就没再继续学习,同时对于这部分知识学习不深入。一直有个误区:自定义编码以及解码服务器就能够解决TCP作为流式协议传输(无消息边界)导致的粘包、半包问题。实则上面这句话有非常大的问题,今日再学习了粘包、半包以及自定义编解码器的关系,纠正已有部分错误认识。

        之前写过一篇Netty中的粘包、半包以及另一篇自定义编解码器的文章:

Netty中半包粘包的产生与处理:短连接、固定长度、固定分隔符、预设长度;redis、http协议举例;网络数据的发送和接收过程_discarded inbound message pooledslicedbytebuf-CSDN博客

自定义协议编解码:Codec(encode\decode)及Sharble注解详解_自定义解码-CSDN博客 

        借此机会对上面内容进行补充以及纠正。

粘包现象以及产生原因

        现象:发送 abc def,接收 abcdef。

        原因:应用层、滑动窗口、Nagle算法。

  • 应用层:接收方 ByteBuf 设置太大(Netty 默认 1024)

  • 滑动窗口:假设发送方 256 bytes 表示一个完整报文,但由于接收方处理不及时且窗口大小足够大,这 256 bytes 字节就会缓冲在接收方的滑动窗口中,当滑动窗口中缓冲了多个报文就会粘包

  • Nagle 算法:会造成粘包

        Nagle算法:也称为延迟确认算法(Delayed Acknowledgment Algorithm)。

        主要目的:减少因频繁发送小数据包而造成的网络拥塞。在TCP连接中,如果应用程序发送了一系列小的数据包,这些数据包可能会在网络中引起额外的开销。Nagle算法通过以下机制来优化数据传输:

        实现方式:

  1. 数据合并:当应用程序连续发送小的数据包时,Nagle算法会将这些数据包合并为一个较大的数据包,然后一起发送。这样可以减少发送的数据包数量,从而减少网络拥塞。

  2. 拥塞窗口:TCP使用拥塞窗口(Congestion Window)来控制发送数据的速率。Nagle算法会根据拥塞窗口的大小来决定是否延迟发送数据包。

  3. 确认等待:当TCP接收到数据包时,它会发送一个确认(ACK)给发送方。Nagle算法会延迟发送这个确认,直到有足够的数据来填充一个最大大小的TCP段,或者直到一个特定的时间间隔过去。

  • 即使发送一个字节,也需要加入 tcp 头和 ip 头,也就是总字节数会使用 41 bytes,非常不经济。因此为了提高网络利用率,tcp 希望尽可能发送足够大的数据,这就是 Nagle 算法产生的缘由

  • 该算法是指发送端即使还有应该发送的数据,但如果这部分数据很少的话,则进行延迟发送

    • 如果 SO_SNDBUF 的数据达到 MSS,则需要发送

    • 如果 SO_SNDBUF 中含有 FIN(表示需要连接关闭)这时将剩余数据发送,再关闭

    • 如果 TCP_NODELAY = true,则需要发送

    • 已发送的数据都收到 ack 时,则需要发送

    • 上述条件不满足,但发生超时(一般为 200ms)则需要发送

    • 除上述情况,延迟发送

半包现象以及产生原因 

        现象:发送 abcdef,接收 abc def

        原因:应用层、滑动窗口、MSS限制。

  • 应用层:接收方 ByteBuf 小于实际发送数据量

  • 滑动窗口:假设接收方的窗口只剩了 128 bytes,发送方的报文大小是 256 bytes,这时放不下了,只能先发送前 128 bytes,等待 ack 后才能发送剩余部分,这就造成了半包

  • MSS 限制:当发送的数据超过 MSS 限制后,会将数据切分发送,就会造成半包

        MSS和MTU的关系:

         MTU(maximum transmission unit):链路层对一次能够发送的最大数据有限制,这个限制称之为MTU,不同的链路设备的MTU值也不相同。

        MSS(maximum segment size)最大段长度:它是MTU刨去tcp头和ip头后剩余能够作为数据传输的字节数。

  • ipv4 tcp 头占用 20 bytes,ip 头占用 20 bytes,因此以太网 MSS 的值为 1500 - 40 = 1460

  • TCP 在传递大量数据时,会按照 MSS 大小将数据进行分割发送

  • MSS 的值在三次握手时通知对方自己 MSS 的值,然后在两者之间选择一个小值作为 MSS

 

粘包、半包解决方案

  • 短连接:能够很好解决粘包,对于半包解决不是很友好(当需要发送字节数超过能够发送最大字节数时就会产生半包)。
  • 固定长度:如果发送数据达不到预设长度,需要填充特定字符,浪费带宽。
  • 固定分隔符:对于消息中含有固定分隔符的消息不友好,无法识别这个分隔符是消息体还是消息边界。
  • 预设长度:每一条消息包含head以及body,head中包含body的长度。

        具体实现方案参考上面博客链接。

自定义编解码器和粘包、半包的关系

        自定义编解码器就是上面提到的第四种实现方案(head[length] body),貌似感觉非常正确不存在问题。

        对于粘包,自定义解码器能够很好处理,此时接收到的消息总量肯定大于需要解析的消息长度,此时不会产生问题。

        对于半包,如果此时发送方一条消息由于某种原因划分为两次发送,此时第一次发送后接收到接收到消息后,首先解析出消息头中的长度,直接使用解析到的长度提取对应的字节数,然而此时并不能提取到对应长度的字节数,此时就会反序列化失败。并不能处理此种情况的半包。

        测试代码:

        下面红色方框中框住的内容即为通过Netty的slice将一条encode后的消息(Message->ByteBuf)划分为两个ByteBuf。如果此时没有上面方框框住的帧解码器,直接调用一次slice后获取到s1,就对此ByteBuf执行channel.writeInbound(s1),由于消息体中没有长度的字节,此时解码失败。

        如果添加上第一个红色方框选中的 LengthFieldBasedFrameDecoder,按照上述方式执行两次slice后依次对于两个ByteBuf执行channel.writeInbound(),此时第一个执行成功后并不会立即解码,而是在第二个channel.writeInbound()执行成功后再解码。

        LengthFieldBasedFrameDecoder:是Netty网络编程的一部分,属于解码器(Decode)的一部分,主要作用将接收到的字节流划分为独立的帧(frames),对于处理基于长度的协议(例如某些二进制协议或自定义文本协议)非常有用。

        添加此组件后,当需要解码的消息长度没有达到指定长度时不会解码,会暂存在缓冲区中,继续等待消息的接收,当达到指定长度后才会将获取指定Length对应的字节数进行Decode。

LengthFieldBasedFrameDecoder详解

  • 基于长度字段的帧解码:这个解码器假设每个消息(或帧)的开始部分包含一个或多个字节,这些字节指示了随后消息体的长度。例如,一个消息可能以一个32位整数开始,表示后续数据的长度。

  • 自动帧拆分LengthFieldBasedFrameDecoder 会自动从接收到的字节流中拆分出完整的帧。它根据长度字段的值来确定帧的边界,并将完整的帧传递给下一个处理环节。

  • 处理粘包和半包问题:在网络编程中,经常会遇到粘包(多个帧粘连在一起)和半包(一个帧被分成多次接收)的问题。LengthFieldBasedFrameDecoder 通过长度字段来正确地拆分帧,从而解决了这些问题。、

  • 可配置的长度字段:开发者可以指定长度字段的偏移量、长度,以及是否包含长度字段本身的长度。这使得它能够适应不同的协议设计。

  • 灵活的解码策略:除了基本的长度字段解码,LengthFieldBasedFrameDecoder 还支持一些高级特性,如调整最大帧长度、处理过长的帧等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2093720.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Pr:代理预设

在 Adobe Premiere Pro 中,“创建代理” Create Proxies对话框中的“代理”预设提供了六种格式选项。 ProRes QuickTime 代理 ProRes 是 Apple 开发的高质量中间编解码器,广泛应用于专业视频编辑领域。它提供了出色的色彩保真度和较低的压缩损失&#xf…

SPR系列单点激光雷达测距传感器|模组之CAN-OPEN软件调试说明

SPR系列单点激光雷达测距传感器|模组利用激光束的时间飞行原理来测量距离。它们发射出一个脉冲激光,并测量激光从传感器发射到击中物体并返回的时间来计算距离。 SPR系列单点激光雷达测距传感器|模组在测量精度要求较高的应用中常被使用,应用范围广泛&a…

PWM(Pulse-width modulation)脉冲宽度调制

PWM(Pulse-width modulation)是脉冲宽度调制 脉冲宽度调制是一种模拟信号电平数字编码方法。脉冲宽度调制PWM是通过将有效的电信号分散成离散形式从而来降低电信号所传递的平均功率的一种方式。所以根据面积等效法则,可以通过对改变脉冲的时…

《高等代数》“么”字型行列式

说明:此文章用于本人复习巩固,如果也能帮助到大家那就更加有意义了。 注:1)“么”字型行列式总共有8种形式 2)“么”字型行列式的求解方法有三种:(1)用长斜边消去短斜边 &#xff0…

Open3D mesh 精细化处理-loop剖分

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 参数详解 返回值 2.2完整代码 三、实现效果 3.1原始mesh 3.2剖分后mesh Open3D点云算法汇总及实战案例汇总的目录地址: Open3D点云算法与点云深度学习案例汇总(长…

Vue 3.5 中的 base watch 函数与 Vue 模块化设计探索

在 Vue.js 的发展历程中,每一个版本的更新都带来了新特性和性能优化,而 Vue 3.5-beta.3 引入的 base watch 函数,虽然名字上听起来像是传统 watch API 的基础版本,但实际上它标志着 Vue 内部架构的一次重要调整。这次调整不仅影响…

Jupyter如何使用Anaconda的虚拟环境

Anaconda的虚拟环境大家应该都知道是什么,我们可以建立多个虚拟环境并在对应的环境中安装不同的python三方库从而运行不同的python项目,那么在jupyter中如何使用Anaconda的虚拟环境呢,今天就为大家分享一个这样的操作教程。 请参考图文进行以…

VSCode设置复制 Ctrl+D想下复制

VSCode 默认向下复制当前行是 shift Alt ↓,但是我们习惯了IDE和webStrom的CtrlD的想下复制.下面是VSCode自定义快捷键. VSCode设置复制 CtrlD想下复制 1.文件->首选项->键盘快捷方式(ctrk 在案ctrs)2.输入 copy line down->右键->更改键绑定3.完成 1.文件->首…

手把手教你从开发进度划分测试

一.单元测试(Unit Testing) 单元测试:软件单元测试的对象是可独立编译或汇编的程序模块。测试的对象是软件测试中的最小单位:模块。 测试阶段:编码后或者编码前(TDD:测试驱动开发)…

记录一些信息收集方法

未完成 百度谷歌关键词搜索(已经很久远了,基本上起不到作用) 查询域名的备案信息 查询相关证书 企查查,天眼查查内部资产 搜索引擎fofa或者钟馗之眼等东西,然后这个里面的东西可以通过http请求头都可以看见&#…

TLB的刷新方式--linux 2.4

TLB刷新的时机(i386) struct tlb_state cpu_tlbstate[NR_CPUS] {[0...NR_CPUS-1] {&init_mm, 0}}; 一般情况各个CPU的cpu_tblstate的state设置成TLBSTATE_OK,表示如果正在使用中的页面目录或页面表内容发生了变化就要刷新TLB的内容。 与vmalloc有关与HIGHM…

工业控制之“什么叫RTO?”

读研究生时,过程控制领域经常涉及“APC”、“RTO”等字眼,导师也经常性提及,现在在工作中也开始提了,可能意识到先进控制的重要性了。 今天谈一下RTO在工业上的应用,曾经和一个博士生对“RTO涉及哪些算法”发生过激烈…

C++ 设计模式——访问者模式

目录 C 设计模式——访问者模式1. 主要组成成分2. 逐步构建访问者模式步骤1: 创建元素接口和具体元素步骤2: 创建抽象访问者和具体访问者步骤3:创建对象结构步骤4: 客户端使用访问者模式 3. 访问者模式 UML 图UML 图解析 4. 访问者模式的优点5. 访问者模式的缺点6. 访问者模式适…

spring security 记住我在web和前后端分离如何使用

一、传统web开发准备工作 如果不懂原理的话,去看上一篇文章:CSDNhttps://mp.csdn.net/mp_blog/creation/editor/141716695 导入需要的依赖包,在传统web页面开发比较简单,我们设置只需要在页面请求参数加上一个remember-me 即可&a…

Linux-gcc/g++使用

文章目录 概念gccg 编译过程预处理(进行宏替换)编译(生成汇编)汇编(生成机器可识别代码)连接(生成可执行文件或库文件)函数库 gcc选项 概念 Linux中的gcc和g是GNU Compiler Collection(GNU编译…

RESP图形化界面远程连接虚拟机Redis教程

参考优质大佬文章: Redis安装以及RESP连接Redis服务器_resp 连接-CSDN博客 《Redis:小白入门》RESP远程连接问题_redis配置文件更改为可以远程连接-CSDN博客 目录 环境 第一步:修改redis配置文件 第二步:关闭Linux防火墙 第三…

功能需求文档-自适应巡航控制ACC

本文以特斯拉Model3为例,展示如何撰写其主动巡航控制功能的功能需求文档;详情请参照用户手册 功能概述 主动巡航控制(ACC)是指系统实时监控车辆前方行驶环境,在设定的速度范围内,通过控制油门和制动,自动调整行驶速度…

Mybatis 潦草笔记

准备工作(创建springboot工程、数据库表、实体类)引入Mybatis的相关依赖,配置Mybatis(数据库连接信息)编写SQL语句(注解/XML) 创建springboot工程 选中两项 MyBatis Framework:My…

分支和循环(上)

目录 1. if语句 1.1 if ​1.2 else 1.3 分支中包含多条语句 1.4 嵌套if 1.5 悬空else问题 2. 关系操作符 3. 条件操作符 4. 逻辑操作符 4.1 逻辑取反操作符 4.2 逻辑与运算符 4.3 逻辑或运算符 4.4 连续:闰年的判断 4.5 短路 5. switch语句 5.1 if语句和switch…

28. 双耳配对 - 配置

1. 概述 通过MAC地址的最后一位的奇偶来判断左右耳 2. 验证 右耳:奇数(主耳)-》BT ADDR: 12:42:22:34:34:6d 左耳:偶数(从耳)-》BT ADDR: 12:42:22:34:34:6c