【计算机网络】如何解决TCP粘包问题?

news/2024/5/21 4:50:09/文章来源:https://blog.csdn.net/weixin_63566550/article/details/129622284

【计算机网络】如何解决TCP粘包问题?

文章目录

  • 【计算机网络】如何解决TCP粘包问题?
    • 如何理解字节流?
    • 如何解决粘包?
      • 固定长度的消息
      • 特殊字符作为边界
      • 自定义消息结构

如何理解字节流?

之所以会说 TCP 是面向字节流的协议,UDP 是面向报文的协议,是因为操作系统对 TCP 和 UDP 协议的发送方的机制不同,也就是问题原因在发送方。

先来说说为什么 UDP 是面向报文的协议?

当用户消息通过 UDP 协议传输时,操作系统不会对消息进行拆分,在组装好 UDP 头部后就交给网络层来处理,所以发出去的 UDP 报文中的数据部分就是完整的用户消息,也就是每个 UDP 报文就是一个用户消息的边界,这样接收方在接收到 UDP 报文后,读一个 UDP 报文就能读取到完整的用户消息。

你可能会问,如果收到了两个 UDP 报文,操作系统是怎么区分开的?

操作系统在收到 UDP 报文后,会将其插入到队列里,队列里的每一个元素就是一个 UDP 报文,这样当用户调用 recvfrom() 系统调用读数据的时候,就会从队列里取出一个数据,然后从内核里拷贝给用户缓冲区。

图片

再来说说为什么 TCP 是面向字节流的协议?

当用户消息通过 TCP 协议传输时,消息可能会被操作系统分组成多个的 TCP 报文,也就是一个完整的用户消息被拆分成多个 TCP 报文进行传输。

这时,接收方的程序如果不知道发送方发送的消息的长度,也就是不知道消息的边界时,是无法读出一个有效的用户消息的,因为用户消息被拆分成多个 TCP 报文后,并不能像 UDP 那样,一个 UDP 报文就能代表一个完整的用户消息。

举个实际的例子来说明。

发送方准备发送 「Hi.」和「I am Xiaolin」这两个消息。

在发送端,当我们调用 send 函数完成数据“发送”以后,数据并没有被真正从网络上发送出去,只是从应用程序拷贝到了操作系统内核协议栈中。

至于什么时候真正被发送,取决于发送窗口、拥塞窗口以及当前发送缓冲区的大小等条件。也就是说,我们不能认为每次 send 调用发送的数据,都会作为一个整体完整地消息被发送出去。

如果我们考虑实际网络传输过程中的各种影响,假设发送端陆续调用 send 函数先后发送 「Hi.」和「I am Xiaolin」 报文,那么实际的发送很有可能是这几种情况。

第一种情况,这两个消息被分到同一个 TCP 报文,像这样:

图片

第二种情况,「I am Xiaolin」的部分随 「Hi」 在一个 TCP 报文中发送出去,像这样:

图片

第三种情况,「Hi.」 的一部分随 TCP 报文被发送出去,另一部分和 「I am Xiaolin」 一起随另一个 TCP 报文发送出去,像这样。

图片

类似的情况还能举例很多种,这里主要是想说明,我们不知道 「Hi.」和 「I am Xiaolin」 这两个用户消息是如何进行 TCP 分组传输的。

因此,我们不能认为一个用户消息对应一个 TCP 报文,正因为这样,所以 TCP 是面向字节流的协议

当两个消息的某个部分内容被分到同一个 TCP 报文时,就是我们常说的 TCP 粘包问题,这时接收方不知道消息的边界的话,是无法读出有效的消息。

要解决这个问题,要交给应用程序

如何解决粘包?

粘包的问题出现是因为不知道一个用户消息的边界在哪,如果知道了边界在哪,接收方就可以通过边界来划分出有效的用户消息。

一般有三种方式分包的方式:

  • 固定长度的消息;
  • 特殊字符作为边界;
  • 自定义消息结构。

固定长度的消息

这种是最简单方法,即每个用户消息都是固定长度的,比如规定一个消息的长度是 64 个字节,当接收方接满 64 个字节,就认为这个内容是一个完整且有效的消息。

但是这种方式灵活性不高,实际中很少用。

特殊字符作为边界

我们可以在两个用户消息之间插入一个特殊的字符串,这样接收方在接收数据时,读到了这个特殊字符,就把认为已经读完一个完整的消息。

HTTP 是一个非常好的例子。

图片

HTTP 通过设置回车符、换行符作为 HTTP 报文协议的边界。

有一点要注意,这个作为边界点的特殊字符,如果刚好消息内容里有这个特殊字符,我们要对这个字符转义,避免被接收方当作消息的边界点而解析到无效的数据。

自定义消息结构

我们可以自定义一个消息结构,由包头和数据组成,其中包头包是固定大小的,而且包头里有一个字段来说明紧随其后的数据有多大。

比如这个消息结构体,首先 4 个字节大小的变量来表示数据长度,真正的数据则在后面。

struct { u_int32_t message_length; char message_data[]; 
} message;

当接收方接收到包头的大小(比如 4 个字节)后,就解析包头的内容,于是就可以知道数据的长度,然后接下来就继续读取数据,直到读满数据的长度,就可以组装成一个完整到用户消息来处理了。

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

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

相关文章

RK3588编译环境Ubuntu20.04编译配置-增加交换内存

迅为提供的编译环境 Ubuntu20.04 默认配置了交换内存是 9G,如果在编译过程中,因内 存不够而编译报错,可以参考本小节进行设置。 这里举例分配 5G 交换内存。 在开始之前,使用命令检查一下您的 ubuntu 的 swap 分区。 sudo swa…

Android进阶面经,面试10余家经验分享,拿到offer真不难~

前言 我们都知道面试大厂主要就是考察程序员技术方向的专业技能,Java开发主要考察的就是Java方面的专业技能,而Android岗位的 专业技能 就是Android程序员面试的重要考察方向。 大厂的招聘条件是明牌的,但技术这一块却难倒了大部分的人。 面…

蓝桥杯刷题冲刺 | 倒计时18天

作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录0.知识点1.乳草的入侵今天写 搜索题 0.知识点 DFS 设计步骤 确定该题目的状态(包括边…

服务器boa移植

服务器boa移植 文章目录服务器boa移植1.下载boa2.解压3.安装词法解析器4.修改源码5. 编译、创建配置文件6.修改配置文件boa.conf7.运行测试1.下载boa Boa Webserver http://www.boa.org/ 2.解压 tar -xf boa-0.94.13.tar.gz3.安装词法解析器 sudo apt-get install bisonsud…

我们为什么不能忽视业务只讲数据治理?_光点科技

数据治理是一项重要的业务实践,可以帮助组织更好地管理和利用数据。然而,一些企业错误地将数据治理视为一项独立的技术实践,而忽略了业务需求。那么,为什么不能忽视业务,只讲数据治理呢?首先,数…

网络基础知识和常用命令

IP、子网掩码、网关、DNS、端口号网络的基本概念客户端:应用 C/S(客户端/服务器) B/S(浏览器/服务器)服务器:为客户端提供服务、数据、资源的机器请求:客户端向服务器索取数据响应:服务器对客户…

H2数据库

H2是一个用Java开发的嵌入式数据库,它本身只是一个类库,可以直接嵌入到应用项目中。 H2简介 H2是一个Java编写的关系型数据库,它可以被嵌入Java应用程序中使用,或者作为一个单独的数据库服务器运行。 H2数据库的前身是 Hypersoni…

线段树SegmentTree

🍏🍐🍊🍑🍒🍓🫐🥑🍋🍉🥝 什么是线段树,它能解决什么样的问题? 文章目录🍭问题引入🥝线段…

代码随想录|day21|二叉树part07 ● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先

530.二叉搜索树的最小绝对差 链接:代码随想录 需要领悟一下二叉树遍历上双指针操作,优先掌握递归 第一次做,理解错误,认为只需要以节点为单位,认为由于是二叉搜索树,所以中序遍历一定是一个连续的有序序列…

vue3+vite+ts 搭建脚手架01创建vite项目并且在项目中初次使用router

vue3vite 搭建脚手架01创建vite项目并且在项目中使用router 1.使用yarn安装vite项目 yarn create vite 搭建vite项目 在开发语言中选择vuets2.安装现在最新的 vue-router4 yarn add vue-router4 在packger中检查是否成功安装3.简单配置router文件 在项目中新建views和…

(19)C#传智:CSS,选择器,样式(第19天)

vs2022保存html项目时,偶尔会有死机,只得强行关闭重新打开。 一、CSS简介 CSS(Cascading Style Sheet)层叠样式表。能让网页制作者有效的定制,改善网页的效果。 CSS是对Html的补充,它很好地控制了网页的显示效果。并实现网页…

A.[OCR]基于PaddleOCR的多视角集装箱箱号检测识别,实现检测识别模型串联推理。

基于PaddleOCR的多视角集装箱箱号检测识别 一、项目介绍 集装箱号是指装运出口货物集装箱的箱号,填写托运单时必填此项。标准箱号构成基本概念:采用ISO6346(1995)标准 标准集装箱箱号由11位编码组成,如:…

UniApp + SpringBoot 实现接入支付宝支付功能和退款功能

一、支付宝开放平台设置 注册支付宝支付功能需要个体工商户或企业才可以!需要有营业执照才能去申请哦! 1、登录到控制台 进入支付宝开放平台 控制台 2、开发设置 3、产品绑定APP支付 如果没有绑定APP支付就会报商家订单参数异常,请重新发起…

Kubernetes学习(八)Helm应用包管理器

为什么需要Helm K8S上的应用对象,都是由特定的资源描述组成,包括deployment、service等。都保存各自文件中或者集中写到一个配置文件,然后kubectl apply –f 部署。 如果应用只由一个或几个这样的服务组成,上面部署方式足够了。…

华为OD机试题,用 Java 解【合并数组】问题 | 含解题说明

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典本篇题目:合并数组 题目 现在有多组整数…

Ubuntu+Nvidia驱动+cuda+cudnn环境配置

目录 Ubuntu系统安装 rtw89版本是需要一定高的内核版本的 Ubuntu Nvidia驱动安装 在附加驱动中安装完nvidia专用驱动,nvidia-smi没有显示驱动信息 安装cuda 安装cudnn Ubuntu系统安装 首先便是双系统的安装,我本身电脑是Windows,装Ubu…

JS: mac台式电脑使用汇总

双指鼠标左滑–回到桌面optaion键 相当于辅助键 optaiona复制 optionx剪切 …操作文件: 苹果文件夹是沙箱模式,要从一个文件夹拖动到另一个文件夹 —调试 iphone连接mac电脑(苹果safari浏览器-开发–xxx的电脑-hap)即可真机调试 –环境 MAC安装node环境:…

《RabbitMQ高阶知识》—消息可靠性

《RabbitMQ高阶知识》— 消息可靠性 文章目录《RabbitMQ高阶知识》— 消息可靠性(1)异常捕获机制(2)AMQP/RabbitMQ的事务机制(3) 发送端确认机制(4) 持久化存储机制(5&am…

519-基于ZU19EG的4路100G 网络 DPU的PCIe 加速计算卡 高速信号处理卡 光纤接入卡 加速计算板卡 ZU19EG板卡

基于ZU19EG的4路100G 网络 DPU的PCIe 加速计算卡 一、板卡概述 本板卡系我司自主设计研发,基于Xilinx公司Zynq UltraScale MPSOC系列SOC XCZU19EG-FFVC1760架构,支持PCIE Gen3x16模式。其中,ARM端搭载一组64-bit DDR4,总容…

基于深度学习的车型识别系统(Python+清新界面+数据集)

摘要:基于深度学习的车型识别系统用于识别不同类型的车辆,应用YOLO V5算法根据不同尺寸大小区分和检测车辆,并统计各类型数量以辅助智能交通管理。本文详细介绍车型识别系统,在介绍算法原理的同时,给出Python的实现代码…