“TCP粘包”不是TCP的问题!
前言
写RPC用了Netty。涉及到粘包拆包问题。想复习一下。发现网上博客多是概念模糊不清。没有触及本质或者没有讲清楚。
遂决定自己写一篇
“TCP粘包”是谁的问题?
首先我们要明确TCP是面向字节流的协议。也就是说我们在应用层想使用TCP来传输数据时,它是无法区分消息的。具体举个例子。
我们想发两条消息。一个100字节,一个1000字节。
我们调用两次TCP的send()。send函数意味着把数据拷贝到发送缓冲区,若缓冲区不够全部写入则会分次写入。
这里我们假设发送缓冲区大小是不变的,仅是TCP的滑动窗口在变。
设我们的缓冲区有1400的大小,此时发送窗口为1100字节。

则写入缓冲区是这个状态,前1100是发送窗口,存放我们要发的两条消息。
但是实际上在缓冲区中都是字节数据,TCP是不会区分消息的,只会把这1100字节视为字节流来进行传输,包装为一个TCP报文来发送。也就是说TCP眼中看这1100个字节就是单纯的字节流,没有我们眼中的消息1,消息2之分。
然后由于Nagle算法,在一段时间后没有等到包,即使没到MSS也会发出。这样这两个消息作为一个TCP包中的数据被发了数据
这就发生了粘包。TCP并不区分应用层的消息边界,只会按发送窗口来发送字节数据。这导致在应用层中本来是两条的消息封装到一个TCP报文,服务端接收会该报文会读出两个粘连的消息。所以需要我们进行协议设计来解决这个粘包的问题。
注意:发送缓冲区等待MSS大小才发送是Nagle协议做的事。下文有介绍。
那么为什么说粘包不是TCP的问题?
因为TCP本身就是针对字节流传输的数据。按消息分割是我们使用者的需求,自然应当有我们自己去解决。
所以准确来说TCP粘包其实是使用TCP传输有边界的消息导致的消息粘连问题。
粘包或半包的原因
滑动窗口让我们可以发送多个数据包而无需等待确认。也即累计确认。
在思考过程中我开始纠结,连续发送多个包的大小是多少,是否都会是标准的MSS。但是实际上这个问题是与粘包半包无关的。TCP把多少字节数据封装为一个TCP报文并没有关系。
问题本质在于TCP字节流传输的性质。
只要基于字节流,那TCP必然无法区分我们应用层划分的多个数据包。无论TCP把数据怎么划分为TCP报文,都有出现粘包半包的可能性。
Nagle算法要MSS再发送是导致粘包半包发生的可能原因,那么我们关掉它,是否可以让缓冲区一有数据就发送呢?是否就能分消息发送了?
Nagle算法
Nagle算法是为了保证TCP报文尽量达到MSS大小。反正基于字节流不必按消息封装报文。只需要按字节流顺序封装即可。为什么要尽量达到MSS呢?
比如我们想发送1000条2字节的消息。若是每次立即发出就是1000个包,而TCP首部有40字节,body却只有2字节。这严重浪费了网络带宽。我们完全可以等待直到可以封装出一个MSS大小的包。
这样一次性发送了MSS长度的数据,只用了一个首部。大大提高了效率。
当然若迟迟等不到MSS大小的数据,它也会直接发送当前大小的数据包。
目前由于Nagle会提高延迟已经很少使用。
那么回到上段末尾的问题,关了Nagle算法是否就没了粘包半包?
当然不是。关了它不代表,操作系统会立即发送缓存区的数据。
假设这一种情况,我调用一次send,数据拷贝到内核缓冲区。由于没有Nagle算法,TCP直接发送。
此时我有send两条消息a和b,那么此时TCP正在发送上一个TCP报文,消息a到达缓冲区时TCP无法封装并发送,紧接着消息b也到达缓冲区。此时两条消息都在缓冲区。TCP再发送还是可能发送粘包半包问题(两条小于MSS则是粘包,大于MSS,则分两条会导致半包)。
同理在接受方的缓冲区仍然可能发生类似问题。因为接受缓冲区中存的是从TCP报文中提出来的字节数据。在我们应用层没有read时,它可能累计多条消息的字节数据。仍然可能发生粘包
结语
所以导致粘包半包的原因其实最底层还是TCP的字节流传输性质。
无论是Nagle算法还是不使用Nagle算法亦或者说MSS的限制,究其本质都是因为字节流协议,本身不区分消息边界,视角是字节。
因此,我们在写传输消息格式的需求,若使用TCP协议,一定要考虑这个问题,制定协议来解决。
回到标题,使用TCP协议发送有消息边界的数据,一定要自己解决。因为TCP很明确就是一个传输字节流的协议,不能按照消息来发送数据。
参考文章:
https://segmentfault.com/a/1190000039691657
相关文章:
“TCP粘包”不是TCP的问题!
前言 写RPC用了Netty。涉及到粘包拆包问题。想复习一下。发现网上博客多是概念模糊不清。没有触及本质或者没有讲清楚。 遂决定自己写一篇 “TCP粘包”是谁的问题? 首先我们要明确TCP是面向字节流的协议。也就是说我们在应用层想使用TCP来传输数据时,…...
Electron项目依赖管理:最佳实践与常见错误
问题一 问题描述: 输入命令 pnpm add electron 后, electron 包在执行 postinstall 脚本时,尝试从网络上下载 Electron 二进制文件,但由于网络问题(如连接超时或代理设置问题),导致下载失败。 λ pnpm a…...
华为数通路由交换HCIP/HCNP
2017-2022年软考高级网络规划设计师真题解析视频!软考复习一定要多做历年真题! 2022年软考网络规划设计师真题解析_哔哩哔哩_bilibili 2024年5月软考网络工程师真题解析合集,考后估分版【综合知识案例分析】 2024年5月软考网络工程师真题解…...
搜索面试题
1、目前怎么构建样本的?如果排序中第5个被点了,前面的作为负样本,后面的不要怎么样;为什么不好,为什么好。 点击作为负样本,曝光未点击作为负样本; 可以这样理解。您提到的排序中第5个被点的对…...
WPF学习(8) --Windows API函数的使用
一、API函数的介绍 1.FindWindow函数 [DllImport("user32.dll", CharSet CharSet.Auto)]public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 功能: FindWindow函数用于根据窗口的类名和窗口名称查找窗口的句柄(IntPtr…...
Linux系统-用户账号文件
文章目录 文件一(passwd) 文件二(shadow) 加密密码部分 举例理解 文件三(gshadow) 文件四(group) 文件五(skel) 文件六(login.defs&#…...
docker配置国内镜像加速
docker配置国内镜像加速 由于国内使用docker拉取镜像时,会经常出现连接超时的网络问题,所以配置Docker 加速来使用国内 的镜像加速服务,以提高拉取 Docker 镜像的速度。 1、备份docker配置文件 cp /etc/docker/daemon.json /etc/docker/da…...
C语言实现排序之堆排序算法
一、堆排序算法 基本思想 堆排序是一种比较有效的排序方法,其基本思想是: 构建最大堆:首先将待排序的数组构建成一个最大堆,即对于每个非叶子节点,它的值都大于或等于其子节点的值。排序:然后将堆顶元素…...
【STM32 Blue Pill编程】-外部中断配置及使用
外部中断配置及使用 文章目录 外部中断配置及使用1、中断介绍2、STM32中的中断3、硬件准备及接线4、GPIO配置5、代码实现在本文中,我们将介绍如何使用 STM32Cube IDE 中的 HAL 库配置和处理外部中断。 我们将通过一个带有按钮和 LED 的示例来演示这一点。 读完本文后,您将能够…...
MySQL 安装与配置教程:单机、主从复制与集群模式
目录 MySQL 简介MySQL 安装MySQL 基础配置MySQL 主从复制配置MySQL 集群配置总结 1. MySQL 简介 MySQL 是一个广泛使用的关系型数据库管理系统,具有高性能、高可靠性和易用性等特点。它支持多种部署模式,包括单机模式、主从复制模式(用于高…...
JavaEE 的相关知识点(一)
一、过滤器 过滤器(Filter)是一个用于对请求和响应进行预处理的组件。过滤器可以在 Java Servlet 规范中使用,通常用于执行一些通用的任务 1、过滤器的作用 过滤器是一种javaEE规范中定义的一种技术,可以让请求达到目标servlet之…...
使用Python实现深度学习模型:智能医疗影像识别与诊断
介绍 智能医疗影像识别与诊断是现代医疗技术的重要应用,通过深度学习模型,可以自动分析和识别医疗影像,提高诊断的准确性和效率。本文将介绍如何使用Python和深度学习技术来实现智能医疗影像识别与诊断。 环境准备 首先,我们需要安装一些必要的Python库: pip install …...
24.给定一个链表,实现一个算法交换每两个相邻节点并返回其头部。要求不能修改列表节点中的值,只能更改节点本身。
24. Swap Nodes in Pairs 题目 给定一个链表,交换每两个相邻节点并返回其头部。要求不能修改列表节点中的值,只能更改节点本身。 Example: Given 1->2->3->4, you should return the list as 2->1->4->3....
Python 通过UDP传输超过64k的信息
Python 通过UDP传输超过64k的信息 在网络编程中,UDP(用户数据报协议)是一种常用的传输协议。与TCP不同,UDP是无连接的,并且不保证数据包的顺序、完整性及交付。尽管如此,UDP因其较低的延迟和开销而被广泛应…...
微服务设计原则——高性能:批量
能批量就不要并发。 如果调用方需要调用我们接口多次才能进行一个完整的操作,那么这个接口设计就可能有问题。 比如获取数据的接口,如果仅仅提供getData(int id)接口,那么使用方如果要一次性获取 20 个数据,它就需要循环遍历调用…...
C:指针学习-指针变量—学习笔记
今日伊雷娜: 目录 前言: 1、字符指针变量 1.1 使用字符指针存放字符 1.2 使用字符指针变量存放字符串 2、数组指针变量 2.1 什么是数组指针变量? 2.2 数组指针变量初始化 2.3 关于数组指针类型的解析 3、函数指针变量 3.1 函数地址 …...
【MySQL 07】表的增删查改 (带思维导图)
文章目录 🌈 一、insert 添加数据⭐ 1. 单行数据 全列插入⭐ 2. 多行数据 指定列插入⭐ 3. 插入否则更新⭐4. 插入否则替换 🌈 二、select 查询数据⭐ 1. select 列🌙 1.1 全列查询🌙 1.2 指定列查询🌙 1.3 查询字段…...
快速上手Git
Git相关概念 Git是一个开源的分布式版本控制系统,由Linus Torvalds在2005年创建,用于有效、高速地处理从小到大的项目版本管理。它是由 Linux 之父 Linus Torvalds 开发的,并已经成为了现代软件开发领域中最流行的版本控制系统之一。 git的工…...
RTC时钟测试
1. 基础知识 Linux 的系统时间有时跟硬件时间是不同步的。 Linux时钟分为系统时钟(System Clock)和硬件(Real Time Clock,简称RTC)时钟。系统时钟是指当前Linux Kernel中的时钟,而硬件时钟则是主板上由电池供电的时钟,这个硬件时钟可以在BIO…...
大数据技术——实战项目:广告数仓(第六部分)报表数据导出至clickhouse
目录 第11章 报表数据导出 11.1 Clickhouse安装 11.2 Clickhouse建表 11.2.1 创建database 11.2.2 创建table 11.3 Hive数据导出至Clickhouse 第11章 报表数据导出 由于本项目最终要出的报表,要求具备交互功能,以及进行自助分析的能力,…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...
链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
