【必会面试题】TCP协议的粘包拆包

目录

      • TCP数据报文结构
      • 粘包
      • 拆包
      • 如何处理粘包和拆包

TCP协议的粘包和拆包是数据传输过程中常见的现象,它们不是TCP协议本身的设计目的,而是基于TCP协议的特性自然产生的结果。

TCP数据报文结构

字段名English Name长度(比特)描述
源端口号Source Port16发送方的端口号,用于标识发送数据的应用程序
目标端口号Destination Port16接收方的端口号,用于标识接收数据的应用程序
序列号Sequence Number32发送的数据段的第一个字节的序列号,用于数据排序与确认
确认号Acknowledgment Number32确认收到对方的序列号,期望收到的下一个数据段的第一个字节序号
数据偏移(DO)Data Offset4报头长度,指示TCP报头有多少个32位字(单位不是比特),最小值5
保留Reserved6未使用,保留为今后使用,目前应置为0
URGUrgent1紧急指针有效标志
ACKAcknowledge1确认标志,表示确认字段有效
PSHPush1提示接收方应该尽快将数据交付给上层协议处理
RSTReset1复位连接标志,用于异常终止连接
SYNSynchronize1同步序号,用于建立连接
FINFinish1结束标志,表示发送方已经完成数据发送任务,可以关闭连接
窗口大小Window Size16通知对方其接收缓冲区的大小
校验和Checksum16包含TCP报头和数据部分的校验和,用于错误检测
紧急指针Urgent Pointer16只有当URG标志为1时有意义,指向紧急数据的最后一个字节后续的第一个字节
选项与填充Options & Padding可变可选字段,用于扩展功能,如最大报文段大小(MSS)等,不足4字节需填充
  • 一个示例
0000 0000 0000 0001 0000 0000 0000 0010  # 源端口:1,目的端口:2
0000 0000 0000 0000 0000 0000 0000 0001  # 序列号:1
0000 0000 0000 0000 0000 0000 0000 0002  # 确认号:2
0101 0000 0000 0000 0000 0000 0000 0000  # 数据偏移:5,保留:0,控制位:010SYN, ACK0000 0000 0000 0010 0000 0000 0000 0000  # 窗口大小:2
0000 0000 0000 0000 0000 0000 0000 0000  # 校验和:0(示例值,实际计算)
0000 0000 0000 0000 0000 0000 0000 0000  # 紧急指针:0
0000 0000 0000 0000 0000 0000 0000 0000  # 选项:无
0101 0101 0101 0101 0101 0101 0101 0101  # 数据:"Hello"ASCII编码

粘包

概念:在TCP协议中,粘包指的是多个TCP报文段在传输过程中被接收端连续接收,而没有明显的边界区分,看起来就像是一个连续的数据包。这是因为TCP是一个面向流的协议,它不对每个应用层消息单独封装。

  • 假设客户端发送了两个数据包,分别是"Hello"和"World"。在没有粘包的情况下,它们应该分别发送。但在粘包的情况下,它们可能被合并为一个数据包发送。
  1. 客户端发送的数据包1(“Hello”):
0000 0000 0000 0001 0000 0000 0000 0010  # 源端口:1,目的端口:2
0000 0000 0000 0000 0000 0000 0000 0001  # 序列号:1
0000 0000 0000 0000 0000 0000 0000 0002  # 确认号:2
... # 其他TCP头部字段
0101 0101 0101 0101 0101  # 数据:"Hello"ASCII编码
  1. 客户端发送的数据包2(“World”):
0000 0000 0000 0001 0000 0000 0000 0010  # 源端口:1,目的端口:2
0000 0000 0000 0001 0000 0000 0000 0006  # 序列号:6(假设)
0000 0000 0000 0000 0000 0000 0000 0007  # 确认号:7(假设)
... # 其他TCP头部字段
0101 0111 0111 0111 0110 1100  # 数据:"World"ASCII编码

在粘包的情况下,接收方可能收到如下的数据包:

0101 0101 0101 0101 0101 0101 1110 1100  # 数据:"HelloWorld"ASCII编码

拆包

概念:与粘包相反,拆包是指发送端的一个较大的TCP数据包在传输过程中被分割成多个较小的数据包到达接收端。这是因为网络层和传输层(TCP)有各自的MTU(最大传输单元)限制,数据包必须适应这些限制才能在网络中传输。

原因

  • MTU限制:不同网络设备和链路可能有不同的MTU,数据包必须被拆分以适应最小的MTU。
  • 拥塞控制:TCP的拥塞控制机制也可能导致数据被拆分,以减缓发送速度,避免网络拥塞。

如何处理粘包和拆包

TCP协议的粘包拆包可能会导致以下问题:

  1. 数据丢失:在拆包过程中,如果某个分片的数据丢失,可能导致整个原始数据无法还原。
  2. 数据错误:粘包情况下,接收端可能将多个数据包误认为是单个数据包,从而导致数据解析错误。
  3. 性能下降:为了解决粘包拆包问题,需要额外的处理机制,这会增加系统的复杂性和计算开销。

一般解决这些问题有以下几种思路:

  1. 定长包头:在每个数据包前加上固定长度的包头,包头中包含数据包的实际长度。这样,接收端可以根据包头中的长度信息来分割数据包。
public class FixedLengthFrameDecoder extends ByteToMessageDecoder {private final int frameLength;public FixedLengthFrameDecoder(int frameLength) {this.frameLength = frameLength;}@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {if (in.readableBytes()< frameLength) {return;}in.markReaderIndex(); // 标记当前读指针位置int dataLength = in.readInt(); // 读取数据长度if (dataLength > frameLength - 4) { // 检查数据长度是否合法in.resetReaderIndex(); // 不合法时重置读指针throw new CorruptedFrameException("data length is larger than the frame length.");}byte[] data = new byte[dataLength];in.readBytes(data);out.add(data);}
}
  1. 分隔符:在数据包之间使用特殊的分隔符作为标识,接收端根据分隔符来分割数据包。这种方法适用于数据包内容不包含分隔符的场景。
public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {private static final byte DELIMITER = '#';@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {int readableBytes = in.readableBytes();int readIndex = in.readerIndex();while (readableBytes > 0) {byte nextByte = in.getByte(readIndex);if (nextByte == DELIMITER) {break;}readableBytes--;readIndex++;}if (readableBytes == 0) {return;}int dataLength = readIndex - in.readerIndex();byte[] data = new byte[dataLength];in.readBytes(data);out.add(data);}
}
  1. 长度前缀:在数据包前加上表示数据长度的字段,接收端根据长度字段来分割数据包。这种方法适用于数据包长度可变的情况。
public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {private static final int LENGTH_FIELD_LENGTH = 4;private static final int LENGTH_FIELD_OFFSET = 0;private static final int LENGTH_ADJUSTMENT = 0;private static final int INITIAL_BYTES_TO_STRIP = LENGTH_FIELD_LENGTH;@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {if (in.readableBytes() < LENGTH_FIELD_LENGTH) {return;}in.markReaderIndex(); // 标记当前读指针位置int dataLength = in.readInt(); // 读取数据长度if (dataLength < 0) { // 检查数据长度是否合法in.resetReaderIndex(); // 不合法时重置读指针throw new CorruptedFrameException("negative length: " + dataLength);}if (in.readableBytes()< dataLength + LENGTH_FIELD_LENGTH) {in.resetReaderIndex(); // 如果可读字节不足以容纳整个数据包,重置读指针return;}in.readerIndex(in.readerIndex() + LENGTH_FIELD_LENGTH); // 跳过长度字段byte[] data = new byte[dataLength];in.readBytes(data);out.add(data);}
}

一般我们通过现有框架如Netty能更方便的解决这些问题。
Netty提供了多种解码器,如FixedLengthFrameDecoder、DelimiterBasedFrameDecoder和LengthFieldBasedFrameDecoder,可以更有效地处理粘包拆包问题。

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

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

相关文章

军用FPGA软件 Verilog语言的编码准测之时钟

军用FPGA软件 Verilog语言的编码准测之时钟 语言 &#xff1a;Verilg HDL EDA工具&#xff1a;ISE、Vivado、Quartus II 军用FPGA软件 Verilog语言的编码准测之时钟一、引言二、基本编程规范之时钟强制准则1----禁止将寄存器的输出直接连接到其他寄存器的时钟管脚。强制准则2--…

ADOQuery中使用Resync解决读取lookup数据不正确的问题

在使用 Delphi2007 的ADOQuery时&#xff0c;遇到一个看到的数据与读取 lookup 数据不一样的问题。 使用 MSSQL数据。有一个存储过程。使用ADOQuery&#xff08;QTY1)获取返回的数据。 如&#xff1a; ID NAME MACHINE QTY 1 JOE XL75…

算法day28

第一题 295. 数据流的中位数 本题我们是求解给定数组的中位数。且由于需要随时给数组添加元素&#xff0c;所以我们要求解该动态数组的中位数&#xff0c;所以本题最关键的就是维护数组在添加元素之后保持有序的排序&#xff0c;这样就能很快的求解中位数&#xff1b; 解法&am…

广州酒吧安全管理:蓝牙可燃气体报警器的实践与检定

随着现代都市生活的丰富多样&#xff0c;酒吧已成为人们休闲娱乐的重要场所。然而&#xff0c;酒吧内大量使用的燃气设备也带来了不小的安全隐患。 如何在确保顾客享受愉悦时光的同时&#xff0c;保障他们的生命财产安全&#xff0c;成为广州各大酒吧经营者亟待解决的问题。 …

通过语言大模型来学习tensorflow框架训练模型(三)

一、模型训练5步骤走 1.数据获取&#xff0c;2&#xff0c;数据处理&#xff0c;3.模型创建与训练&#xff0c;4 模型测试与评估&#xff0c;5.模型预测 二、tensorflow数据获取 在TensorFlow中&#xff0c;数据获取和预处理是构建深度学习模型的重要步骤。TensorFlow提供了多…

Linux之history历史指令查看

Linux之history历史指令查看 history命令用来查看曾经输出过的命令。 命令格式 history [选项]选项 n 显示最近条记录 -c 清除历史记录&#xff0c;但是此项清除只是清除当前shell&#xff0c;从新连接还是有历史记录显示命令时间设置 命令history显示时间戳。此命令只是临…

每日一练:攻防世界:北京地铁

首先是找图片隐写 在这里可以看到一串类似base64格式的字符串 再结合题目&#xff0c;这应该就是明文了&#xff0c;要AES解密&#xff0c;还需要密钥&#xff0c;提示要看图片本身&#xff0c;那密钥可能藏在里面&#xff0c;找了半天没找到&#xff0c;参考师傅的wp&#x…

外盘黄金期货需要注意什么?

为大家整理了关于黄金做单的五大原则&#xff0c;相信对于新手投资者来说肯定会产生一定的帮助。  1、看多空&#xff1a;主要有两种方法&#xff0c;基本面判断和技术面判断&#xff0c;基本面判断&#xff0c;主要是借助基本信息面&#xff0c;如政策。供需&#xff0c;产量…

idea远程调试docker容器内正在运行的线上项目

1.重新编写Dockerfile文件 在原本的Dockerfile上新增参数 就是 运行jar包增加调试参数 增加调试暴漏的端口号 -agentlib:jdwptransportdt_socket,servery,suspendn,address*:50052.在运行docker容器的时候增加暴漏端口5005 3.打开idea就是正在运行的项目 4.选择远程配置 5.配…

渗透测试和红蓝对抗是什么?二者之间有何区别?

在网络安全这个庞大的体系中&#xff0c;渗透测试、红蓝对抗是比较常见的专业名词&#xff0c;承担着非常重要的作用&#xff0c;那么什么是渗透测试、红蓝对抗?红蓝对抗和渗透测试有什么区别?小编通过这篇文章为大家介绍一下。 渗透测试 渗透测试&#xff0c;是通过模拟黑…

H5漂流瓶交友源码|社交漂流瓶H5源码 附安装教程

H5漂流瓶交友源码|社交漂流瓶H5源码 附安装教程 搭建教程 环境&#xff1a;Nginx 1.20.1-MySQL 5.6.50-PHP-7.3 上传源码至网站根目录&#xff0c;创建并导入数据库 数据库信息修改&#xff1a;/config/database.php 网站运行目录/public 配置文件加入&#xff08;从24行…

实验训练题目

一、基本数据类型 &#xff08;一&#xff09;利用所学字符串相关知识解决下列问题 1 、判断自己的学号是否以“ 2 ”结尾。 2 、根据自己的学号输出自己的学院。 3 、计算自己学号的长度。 4 、对自己的学号进行分割。 &#xff08;二&#xff09;根据资料 1 利用所学…

第2章 Rust初体验4/8:提供标准库之外功能的Library Crate:简化包管理和依赖管理:猜骰子冷热游戏

讲动人的故事,写懂人的代码 2.4 故事2: 生成点数之和的随机答案 又是新的一天,大家的培训课又开始了哦!现在,我们的学员们开始用三种语言来实现故事2,加油! 2.4.1 Rust版故事2 2.4.1.1 提供标准库之外功能的Library Crate:简化包管理和依赖管理 贾克强:“我们的故事…

【云岚到家】-day03-1-门户等缓存方案选择

【云岚到家】-day03-1-门户-缓存方案选择 1 门户1.1 门户简介1.2 常见的技术方案1.2.1 需求1.2.2 常见门户1.2.2.1 Web门户1.2.2.2 移动应用门户1.2.2.3 总结 2 缓存技术方案2.1 需求分析2.1.1 界面原型2.2.2 缓存需求 3 SpringCache入门3.1 基础概念3.1.1 Redis客户端3.1.2 Sp…

0 配置

文章目录 创建用户第一个命令&#xff1a;第二个命令组合&#xff1a; 防火墙端口开放上传文件改权限websocketapplication.yaml 创建用户 在 CentOS 7.9 中&#xff0c;使用 useradd 命令创建用户和 groupadd 命令创建用户组时&#xff0c;有一些选项和参数用于指定不同类型的…

基于uni-app与图鸟UI打造的各领域移动端模板大赏

随着移动互联网的迅猛发展&#xff0c;各类移动端应用层出不穷&#xff0c;为了帮助企业快速搭建高效、美观的移动平台&#xff0c;我们基于强大的uni-app与图鸟UI&#xff0c;精心打造了不下于40套覆盖多个领域的移动端模板。今天&#xff0c;就让我们一起领略这些模板的风采吧…

C++的封装(十三):迭代器问题

前面讨论了linux风格的链表的做法。那个例子没有用到迭代器。现在把它加上: class list { public:struct node {pair<node*, node*>link;} handle;list() { handle.link.firsthandle.link.second&handle; }~list() {}public:struct iterator_st {node *p;};class it…

PaddleOCR学习——PP-OCR系列

相关知识前置&#xff1a; PP-LCNet PP-LCNetV3 PP-LCNetV3系列模型是PP-LCNet系列模型的延续&#xff0c;覆盖了更大的精度范围&#xff0c;能够适应不同下游任务的需要。PP-LCNetV3系列模型从多个方面进行了优化&#xff0c;提出了可学习仿射变换模块&#xff0c;对重参数…

webpack之HMR

什么是HMR Hot Module Replacement是指当我们对代码修改并保存后&#xff0c;webpack将会对代码进行重新打包&#xff0c;并将新的模块发送到浏览器端&#xff0c;浏览器用新的模块替换掉旧的模块&#xff0c;以实现在不刷新浏览器的前提下更新页面 使用HMR 安装 yarn add …

Fluid 1.0 版发布,打通云原生高效数据使用的“最后一公里”

作者&#xff1a;顾荣 前言 得益于云原生技术在资源成本集约、部署运维便捷、算力弹性灵活方面的优势&#xff0c;越来越多企业和开发者将数据密集型应用&#xff0c;特别是 AI 和大数据领域应用&#xff0c;运行于云原生环境中。然而&#xff0c;云原生计算与存储分离架构虽…