「 计算机网络 」TCP的粘包拆包问题

news/2024/12/2 16:42:26/

「 计算机网络 」TCP的粘包/拆包问题

参考&鸣谢

大病初愈,一分钟看懂TCP粘包拆包 雷小帅

TCP 的粘包拆包以及解决方案 一乐说


文章目录

  • 「 计算机网络 」TCP的粘包/拆包问题
    • 一、前言
    • 二、为什么UDP没有粘包
    • 三、粘包拆包发生场景
    • 四、常见的解决方案
    • 五、Netty对粘包和拆包问题的处理
    • 六、小结


一、前言

当我们在进行网络传输时,由于各种原因,数据包的发送和接收可能会出现粘包和拆包的问题。粘包和拆包都是数据分组错误的情况,其中粘包指的是多个数据包被合并成一个,而拆包则是一个数据包被拆成了多个数据包。这些问题会导致数据的解析和处理变得困难,进而影响整个系统的稳定性和可靠性。

TCP协议是一种面向连接、可靠的传输协议,在网络传输中被广泛应用。TCP采用了一系列机制来解决粘包和拆包问题,保证数据的可靠传输。本文将介绍TCP协议如何解决粘包和拆包问题,让读者更深入地了解TCP协议的传输特点和实现方式。


二、为什么UDP没有粘包

粘包拆包问题在数据链路层、网络层以及传输层都有可能发生。日常的网络应用开发大都在传输层进行,由于UDP有消息保护边界,不会发生粘包拆包问题,因此粘包拆包问题只发生在TCP协议中。

UDP协议没有粘包的概念,因为它是面向无连接的协议。在UDP中,每个数据报都是独立的,发送方发送多少数据报,接收方就会收到多少数据报。UDP不会对数据进行任何拆分或重组,也不会对数据包进行排序,因此不存在数据包粘连的问题。另外,UDP中也没有类似于TCP的流量控制和拥塞控制机制,所以即使出现丢包或延迟,发送方也不会调整发送速率,从而导致粘包的情况。


三、粘包拆包发生场景

因为TCP是面向流,没有边界,而操作系统在发送TCP数据时,会通过缓冲区来进行优化,例如缓冲区为1024个字节大小。

如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,这就形成了粘包问题。

如果一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是拆包。

关于粘包和拆包可以参考下图的几种情况:

图片

粘包/拆包

上图中演示了以下几种情况:

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

四、常见的解决方案

对于粘包和拆包问题,常见的解决方案有四种:

  • 发送端将每个包都封装成固定的长度,比如100字节大小。如果不足100字节可通过补0或空等进行填充到指定长度;
  • 发送端在每个包的末尾使用固定的分隔符,例如\r\n。如果发生拆包需等待多个包发送过来之后再找到其中的\r\n进行合并;例如,FTP协议;
  • 将消息分为头部和消息体,头部中保存整个消息的长度,只有读取到足够长度的消息之后才算是读到了一个完整的消息;
  • 通过自定义协议进行粘包和拆包的处理。

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

Netty对解决粘包和拆包的方案做了抽象,提供了一些解码器(Decoder)来解决粘包和拆包的问题。如:

  • LineBasedFrameDecoder:以行为单位进行数据包的解码;
  • DelimiterBasedFrameDecoder:以特殊的符号作为分隔来进行数据包的解码;
  • FixedLengthFrameDecoder:以固定长度进行数据包的解码;
  • LenghtFieldBasedFrameDecode:适用于消息头包含消息长度的协议(最常用);

基于Netty进行网络读写的程序,可以直接使用这些Decoder来完成数据包的解码。对于高并发、大流量的系统来说,每个数据包都不应该传输多余的数据(所以补齐的方式不可取),LenghtFieldBasedFrameDecode更适合这样的场景。


六、小结

TCP协议粘包拆包问题是因为TCP协议数据传输是基于字节流的,它不包含消息、数据包等概念,需要应用层协议自己设计消息的边界,即消息帧(Message Framing)。如果应用层协议没有使用基于长度或者基于终结符息边界等方式进行处理,则会导致多个消息的粘包和拆包。

针对 TCP 粘包拆包的现象,常见的解决思路如下:

(1)发送端给每个数据包添加包首部

(2)发送端将每个数据包封装为固定长度

(3)可以在数据包之间设置边界(特殊字符串分割)。

虽然很多框架中都有现成的解决方案,比如Netty,但底层的原理我们还是要清楚的,而且还要知道有这么回事,才能更好的结合场景进行使用。


http://www.ppmy.cn/news/78606.html

相关文章

爬虫Requests库是什么,怎么用?

Requests库是Python中一个非常流行的HTTP请求库,它可以方便地发送HTTP请求并处理响应。在本文中,我们将介绍Requests库的基本用法,包括发送GET和POST请求、设置请求头、处理响应等。 一、安装Requests库 在使用Requests库之前,我…

C++入门篇---(命名空间、缺省参数、以及输入、输出)

前言 c 我来了,恭喜牛牛解锁新世界.开启c的学习之旅. 🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯C语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>:讲解C…

Why Rust Android

Android Rust https://source.android.google.cn/docs/setup/build/rust/building-rust-modules/overview?hlzh-cn 像Java和Kotlin这样的托管语言是Android应用程序开发的最佳选择。这些语言旨在实现易用性、可移植性和安全性。Android 运行时 (ART) …

k8s pv pvc的介绍|动态存储|静态存储

k8s pv pvc的介绍|动态存储|静态存储 1 emptyDir存储卷2 hostPath存储卷3 nfs共享存储卷4 PVC 和 PVNFS使用PV和PVC 4 搭建 StorageClass NFS,实现 NFS 的动态 PV 创建 1 emptyDir存储卷 当Pod被分配给节点时,首先创建emptyDir卷,并且只要该…

2023年,千万别裸辞....

作为IT行业的大热岗位——软件测试,只要你付出了,就会有回报。说它作为IT热门岗位之一是完全不虚的。可能很多人回说软件测试是吃青春饭的,但放眼望去,哪个工作不是这样的呢?会有哪家公司愿意养一些闲人呢?…

Pycharm 配置jupyter notebook 且Windos 安装vim编辑器

请记住要想让你的python成功安装jupyter notebook ,你的python最好使用p大于等于python3.7 最好不要在python2大版本中安装jupyternotebook 这个会报错,需要你改一些配置文件,除非你想挑战一下自己,不过后面我会尝试在python2大版…

Elasticsearch:Explicit mapping - 显式映射

显式映射相比较动态映射(Dynamic mapping)是需要我们在索引创建时就定义字段及其类型。这个和我们传统的 RDMS 数据库一样,在我们写入数据到数据库之前,我们需要工整地定义好每个字段及其类型和长度。Elasticsearch 既可以使用显式…

前端跨域解决方案

目录 🦁 项目场景网络请求跨域error 🦁 问题描述🦁 原因分析🦁 解决方案目前主流的跨域解决方案有两种1. CrossOrigin注解:1.1 方法上方1.2 类上方 2.前端解决 proxy 🦁 项目场景 网络请求跨域error 一般会…