TCP 粘包/拆包

文章目录

    • 概述
    • 粘包拆包发生场景
    • 解决TCP粘包和拆包问题的常见方法
    • Netty对粘包和拆包问题的处理
    • 小结

概述

TCP的粘包和拆包问题往往出现在基于TCP协议的通讯中,比如RPC框架、Netty等
TCP 粘包/拆包 就是你基于 TCP 发送数据的时候,出现了多个字符串“粘”在了一起或者
一个字符串被“拆”开的问题。
TCP粘包和拆包是指在使用TCP协议进行数据传输时,发送方发送的数据包与接收方接收的数据包之间出现了不符合预期的粘连或拆分情况。
TCP粘包:TCP粘包指的是发送方在一次发送中将多个逻辑上独立的数据包粘合成一个大的数据包发送,而接收方可能会将这个大的数据包误认为是多个小的数据包。这种情况下,接收方需要根据自身的接收缓冲区大小和数据包的边界进行数据的解析,容易导致数据解析错误或混乱。
TCP拆包:TCP拆包指的是发送方在一次发送中将一个逻辑上独立的数据包拆分成多个小的数据包发送,而接收方可能会将这些小的数据包合并成一个大的数据包。这种情况下,接收方需要对接收到的数据进行拆包处理,以获取完整的数据包。
1、要发送的数据大于 TCP 发送缓冲区剩余空间大小,将会发生拆包。
2、待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。
3、要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包。
4、接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。

粘包拆包发生场景

因为TCP是面向流,没有边界,而操作系统在发送TCP数据时,会通过缓冲区来进行优化,例如缓冲区为1024个字节大小。
如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,这就形成了粘包问题。
如果一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是拆包。
关于粘包和拆包可以参考下图的几种情况:
在这里插入图片描述

上图中演示了以下几种情况:
● 正常的理想情况,两个包恰好满足TCP缓冲区的大小或达到TCP等待时长,分别发送两个包;
● 粘包:两个包较小,间隔时间短,发生粘包,合并成一个包发送;
● 拆包:一个包过大,超过缓存区大小,拆分成两个或多个包发送;
● 拆包和粘包:Packet1过大,进行了拆包处理,而拆出去的一部分又与Packet2进行粘包处理。

解决TCP粘包和拆包问题的常见方法

  1. 消息长度固定:发送方在每个数据包中添加固定长度的消息头,用于表示后续数据包的长度。接收方根据消息头中的长度信息来正确解析数据包,从而避免粘包和拆包问题。
  2. 特殊字符分隔:发送方在数据包之间插入特殊字符(如换行符或其他预先约定好的字符)作为分隔符,接收方根据特殊字符来切分数据包。这种方法需要保证特殊字符不会出现在实际数据中,否则会引起解析错误。
  3. 消息头+消息体:发送方在每个数据包中添加消息头,消息头包含实际数据的长度信息。接收方首先读取消息头中的长度信息,然后按照长度读取对应数量的字节作为实际数据。
  4. 使用消息边界:在传输过程中,发送方和接收方约定好数据包的边界,例如每个数据包以换行符结尾。接收方根据约定的边界来正确解析数据包,从而避免粘包和拆包问题。
  5. 引入应用层协议:在TCP之上构建应用层协议,该协议负责定义数据包的格式和解析规则。通过自定义协议来规范数据包的传输和解析,从而有效解决粘包和拆包问题。
    选择哪种方法来解决TCP粘包和拆包问题,取决于具体的应用场景和需求。需要注意的是,在实际开发中,可能需要综合应用多种方法来解决复杂的粘包和拆包情况。
    ● 发送端将每个包都封装成固定的长度,比如100字节大小。如果不足100字节可通过补0或空等进行填充到指定长度;
    ● 发送端在每个包的末尾使用固定的分隔符,例如\r\n。如果发生拆包需等待多个包发送过来之后再找到其中的\r\n进行合并;例如,FTP协议;
    ● 将消息分为头部和消息体,头部中保存整个消息的长度,只有读取到足够长度的消息之后才算是读到了一个完整的消息;
    ● 通过自定义协议进行粘包和拆包的处理。

Netty对粘包和拆包问题的处理

Netty对解决粘包和拆包的方案做了抽象,提供了一些解码器(Decoder)来解决粘包和拆包的问题。如:
● LineBasedFrameDecoder:以行为单位进行数据包的解码;
● DelimiterBasedFrameDecoder:以特殊的符号作为分隔来进行数据包的解码;
● FixedLengthFrameDecoder:以固定长度进行数据包的解码;
● LenghtFieldBasedFrameDecode:适用于消息头包含消息长度的协议(最常用);
基于Netty进行网络读写的程序,可以直接使用这些Decoder来完成数据包的解码。对于高并发、大流量的系统来说,每个数据包都不应该传输多余的数据(所以补齐的方式不可取),LenghtFieldBasedFrameDecode更适合这样的场景。

小结

TCP协议粘包拆包问题是因为TCP协议数据传输是基于字节流的,它不包含消息、数据包等概念,需要应用层协议自己设计消息的边界,即消息帧(Message Framing)。如果应用层协议没有使用基于长度或者基于终结符息边界等方式进行处理,则会导致多个消息的粘包和拆包。
虽然很多框架中都有现成的解决方案,比如Netty,但底层的原理我们还是要清楚的,而且还要知道有这么会事,才能更好的结合场景进行使用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

查看网络配置的ipconfig命令

ipconfig是调试计算机网络的常用命令,通常大家使用它显示计算机中网络适配器的IP地址、子网掩码及默认网关。其实这只是ipconfig的不带参数用法,而它的带参数用法,在网络中应用也是相当不错的。 1.语法 ipconfig [/all] [/renew[Adapter]] [/…

(四)elasticsearch 源码之索引流程分析

https://www.cnblogs.com/darcy-yuan/p/17024341.html 1.概览 前面我们讨论了es是如何启动,本文研究下es是如何索引文档的。 下面是启动流程图,我们按照流程图的顺序依次描述。 其中主要类的关系如下: 2. 索引流程 (primary) 我们用postman发送请求&…

【Java八股面试系列】JVM-class文件结构

Class文件结构总结 根据 Java 虚拟机规范,Class 文件通过 ClassFile 定义,有点类似 C 语言的结构体。我们之前都是使用javap命令来对字节码文件进行反编译查看的,我们可以使用WinHex软件(Mac平台可以使用010 Editor)来…

如何决定K8S Pod的剔除优先级

在Kubernetes(k8s)中,当节点资源面临压力时,如何决定Pod的优先级是一个关键问题。在Kubernetes 1.8版本之后,引入了基于Pod优先级的调度策略,即Pod Priority Preemption。这种策略允许在资源不足的情况下&a…

git命令远程仓库推送本地项目报错了,解决方案

如果你在使用git命令上传本地项目到远程仓库遇到了如下错误: Updates were rejected because the tip of your current branch is behind。n 别慌,肯定是你的远程仓库里面有原始文件,需要你提前进行一下合并操作,然后才能使用pu…

蓝桥杯嵌入式第8届真题(完成) STM32G431

蓝桥杯嵌入式第8届真题(完成) STM32G431 题目 分析和代码 对比第六届和第七届,这届的题目在逻辑思维上确实要麻烦不少,可以从题目看出,这届题目对时间顺序的要求很严格,所以就可以使用状态机的思想来编程,拿到类似题…

MyBatis多数据源以及动态切换实现(基于SpringBoot 2.7.x)

MyBatis多数据源以及动态切换实现可以实现不同功能模块可以对应到不同的数据库&#xff0c;现在就让我们来讲解一下。 目录 一、引入Maven二、配置文件三、实现多数据源四、动态切换数据源 一、引入Maven 注意&#xff1a;博主这边使用的springboot版本是2.7.14的 <!-- htt…

thinkphp6入门(19)-- 中间件向控制器传参

可以通过给请求对象赋值的方式传参给控制器&#xff08;或者其它地方&#xff09;&#xff0c;例如 <?phpnamespace app\middleware;class Hello {public function handle($request, \Closure $next){$request->hello ThinkPHP;return $next($request);} } 然后在控制…

类图(Class diagram)

类图主要是用来展现软件系统中的类、接口以及它们之间的静态结构 。 一、元素 1、类 ​ 从上到下分为三部分&#xff0c;分别是类名、属性和操作。 类名是必须有的。​类如果有属性&#xff0c;则每一个属性必须有一个名字&#xff0c;另外还可以有其他的描述信息&#xff…

论文阅读-通过云特征增强的深度学习预测云工作负载转折点

论文名称&#xff1a;Cloud Workload Turning Points Prediction via Cloud Feature-Enhanced Deep Learning 摘要 云工作负载转折点要么是代表工作负载压力的局部峰值点&#xff0c;要么是代表资源浪费的局部谷值点。预测这些关键点对于向系统管理者发出警告、采取预防措施以…

选择大语言模型:2024 年开源 LLM 入门指南

作者&#xff1a;来自 Elastic Aditya Tripathi 如果说人工智能在 2023 年起飞&#xff0c;这绝对是轻描淡写的说法。数千种新的人工智能工具被推出&#xff0c;人工智能功能被添加到现有的应用程序中&#xff0c;好莱坞因对这项技术的担忧而戛然而止。 甚至还有一个人工智能工…

【网站项目】038汽车养护管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

sql实现将某一列下移一行

问题 实现如下图所示的 max_salary 下移一行 方法&#xff1a;使用开窗函数 select max_salary, max(max_salary) over(order by max_salary asc rows between 1 PRECEDING and 1 PRECEDING) max_salary_plus from jobs

电商小程序02数据源设计

上一篇我们讲解了电商小程序的需求分析&#xff0c;分析了需要具备的功能并且绘制了系统原型。有了原型之后下一步的事情就是根据原型来设计数据源。 数据源就像盖房子打地基一样&#xff0c;地基打不好&#xff0c;楼可能就盖不高&#xff0c;盖起来要再想调整就比较困难。 …

使用Qt创建项目 Qt中输出内容到控制台 设置窗口大小和窗口标题 Qt查看说明文档

按windows键&#xff0c;找到Qt Creator &#xff0c;打开 一.创建带模板的项目 新建项目 设置项目路径QMainWindow是带工具栏的窗口。 QWidget是无工具栏的窗口。 QDuakig是对话框窗口。创建好的项目如下&#xff1a; #include "widget.h"// 构造函数&#xff…

Windows系统安装Flink及实现MySQL之间数据同步

Apache Flink是一个框架和分布式处理引擎&#xff0c;用于对无界和有界数据流进行有状态计算。Flink的设计目标是在所有常见的集群环境中运行&#xff0c;并以内存执行速度和任意规模来执行计算。它支持高吞吐、低延迟、高性能的流处理&#xff0c;并且是一个面向流处理和批处理…

03 动力云客项目之登录功能后端实现

创建项目 使用Spring initializr初始化项目 老师讲的是3.2.0, 但小版本之间问题应该不大.

14.0 Zookeeper环球锁实现原理

全局锁是控制全局系统之间同步访问共享资源的一种方式。 下面介绍zookeeper如何实现全民锁&#xff0c;讲解他锁和共享锁两类全民锁。 排他锁 排他锁&#xff08;Exclusive Locks&#xff09;&#xff0c;又被称为写锁或独占锁&#xff0c;如果事务T1对数据对象O1加上排他锁…

2023年09月CCF-GESP编程能力等级认证C++编程一级真题解析

一、单选题(共15题,共30分) 第1题 我们通常说的“内存”属于计算机中的( )。 A:输出设备 B:输入设备 C:存储设备 D:打印设备 答案:C 第2题 以下C++不可以作为变量的名称的是( )。 A:redStar B:RedStar C:red_star D:red star 答案:D 第3题 C++表达式…

Linux C/C++ 原始套接字:打造链路层ping实现

在C/C中&#xff0c;我们可以使用socket函数来创建套接字。我们需要指定地址族为AF_PACKET&#xff0c;协议为htons(ETH_P_ALL)来捕获所有传入和传出的数据包。 可以使用sendto和recvfrom函数来发送和接收数据包。我们需要构建一个合法的链路层数据包&#xff0c;在数据包的头…