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

2024-06-14 13:28

本文主要是介绍【必会面试题】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,可以更有效地处理粘包拆包问题。

这篇关于【必会面试题】TCP协议的粘包拆包的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1060533

相关文章

Java如何接收并解析HL7协议数据

《Java如何接收并解析HL7协议数据》文章主要介绍了HL7协议及其在医疗行业中的应用,详细描述了如何配置环境、接收和解析数据,以及与前端进行交互的实现方法,文章还分享了使用7Edit工具进行调试的经... 目录一、前言二、正文1、环境配置2、数据接收:HL7Monitor3、数据解析:HL7Busines

QT实现TCP客户端自动连接

《QT实现TCP客户端自动连接》这篇文章主要为大家详细介绍了QT中一个TCP客户端自动连接的测试模型,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录版本 1:没有取消按钮 测试效果测试代码版本 2:有取消按钮测试效果测试代码版本 1:没有取消按钮 测试效果缺陷:无法手动停

荣耀嵌入式面试题及参考答案

在项目中是否有使用过实时操作系统? 在我参与的项目中,有使用过实时操作系统。实时操作系统(RTOS)在对时间要求严格的应用场景中具有重要作用。我曾参与的一个工业自动化控制项目就采用了实时操作系统。在这个项目中,需要对多个传感器的数据进行实时采集和处理,并根据采集到的数据及时控制执行机构的动作。实时操作系统能够提供确定性的响应时间,确保关键任务在规定的时间内完成。 使用实时操作系统的

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

一些其他面试题

阿里二面:那你来说说定时任务?单机、分布式、调度框架下的定时任务实现是怎么完成的?懵了。。_哔哩哔哩_bilibili 1.定时算法 累加,第二层每一个格子是第一层的总时间400 ms= 20 * 20ms 2.MQ消息丢失 阿里二面:高并发场景下引进消息队列有什么问题?如何保证消息只被消费一次?真是捏了一把汗。。_哔哩哔哩_bilibili 发送消息失败

zookeeper相关面试题

zk的数据同步原理?zk的集群会出现脑裂的问题吗?zk的watch机制实现原理?zk是如何保证一致性的?zk的快速选举leader原理?zk的典型应用场景zk中一个客户端修改了数据之后,其他客户端能够马上获取到最新的数据吗?zk对事物的支持? 1. zk的数据同步原理? zk的数据同步过程中,通过以下三个参数来选择对应的数据同步方式 peerLastZxid:Learner服务器(Follo

【Go】go连接clickhouse使用TCP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么                      🎵 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time""github.com/ClickHouse/clickhouse-go/v2")func main(

java常用面试题-基础知识分享

什么是Java? Java是一种高级编程语言,旨在提供跨平台的解决方案。它是一种面向对象的语言,具有简单、结构化、可移植、可靠、安全等特点。 Java的主要特点是什么? Java的主要特点包括: 简单性:Java的语法相对简单,易于学习和使用。面向对象:Java是一种完全面向对象的语言,支持封装、继承和多态。跨平台性:Java的程序可以在不同的操作系统上运行,称为"Write once,

2024.9.8 TCP/IP协议学习笔记

1.所谓的层就是数据交换的深度,电脑点对点就是单层,物理层,加上集线器还是物理层,加上交换机就变成链路层了,有地址表,路由器就到了第三层网络层,每个端口都有一个mac地址 2.A 给 C 发数据包,怎么知道是否要通过路由器转发呢?答案:子网 3.将源 IP 与目的 IP 分别同这个子网掩码进行与运算****,相等则是在一个子网,不相等就是在不同子网 4.A 如何知道,哪个设备是路由器?答案:在 A

图解TCP三次握手|深度解析|为什么是三次

写在前面 这篇文章我们来讲解析 TCP三次握手。 TCP 报文段 传输控制块TCB:存储了每一个连接中的一些重要信息。比如TCP连接表,指向发送和接收缓冲的指针,指向重传队列的指针,当前的发送和接收序列等等。 我们再来看一下TCP报文段的组成结构 TCP 三次握手 过程 假设有一台客户端,B有一台服务器。最初两端的TCP进程都是处于CLOSED关闭状态,客户端A打开链接,服务器端