`

环形队列解决TCP粘包问题

阅读更多

转自http://blog.csdn.net/u013898698/article/details/54846084

1、环形缓冲区的实现原理

环形缓冲区通常有一个读指针和一个写指针。读指针指向环形缓冲区中可读的数据,写指针指向环形缓冲区中可写的缓冲区。通过移动读指针和写指针就可以实现缓冲区的数据读取和写入。在通常情况下,环形缓冲区的读用户仅仅会影响读指针,而写用户仅仅会影响写指针。如果仅仅有一个读用户和一个写用户,那么不需要添加互斥保护机制就可以保证数据的正确性。如果有多个读写用户访问环形缓冲区,那么必须添加互斥保护机制来确保多个用户互斥访问环形缓冲区。

 

问题描述
    我在使用Socket接收消息时,将会触发一个接收函数。(BCB中的是ClientRead函数)所以我在此函数处接收信息,并做相应处理。那问题来了:由于传输的数据包都是我自定义的,我明确的知道长度为多多少。可实际效果却是,有时候接不够我期待的长度,而甚至有时候一次接收的数据包长度竟然比我预期的要长10个字节。当时只有设定条件将不满足我预期长度的数据包丢弃。

 

问题分析

看了上面描述,想必大家也明白我的错误在哪了吧?实际是我对Socket的接收机制理解有误。TCP/IP只保证发送包按顺序到达目的地,但可能由于网络状况他会自动分包发送,这样就导致接收端的接受函数每次提交时只有若干数据,不一定是我预期的一个完整的包。可以这样理解,发过来的实际是一个‘流’。

看来要很好的解决这个问题,那就只有先将接收的数据保存起来,再来做处理。

 

处理模型

为了要保存接收数据,我们首先就要建立一个缓冲区。那第一个问题来了:由于我们要接收的信息是不可预知的,那难道这个缓冲区要无限的扩容?

可我们的实际PC内存肯定是有限的,所以我们必须建立一套内存缓冲区可以被反复利用的机制 —— 环形队列。

我们用图来说明环形队列的工作原理:

 

 

图1 蓝色为写入的数据,绿色为已经读取处理的数据

看上图1,在正常状态下:Write指针在写入数据,而Read指针在Write指针之前,说明缓冲区后端还有空余空间。

在指针回滚状态下:Write指针在Read指针之前,说明缓冲区的前端已经有空闲的空间。

除了这两种状态外,我们不得不再考虑一种即将错误状态:

 

图2蓝色为写入的数据,棕红色为未处理的数据

看图2,无足够空间:当Write指针回滚,发现无足够空间,将和Read指针发生交集(虚点部分)这显然是不合理的。一部分未处理数据将被覆盖破环。所以我们必须重新调整整个缓冲区。

重新分配调整:当遇到空间不足,不能实现Write指针回滚的情况,我们只有重新开辟一个更大一点的缓冲区,并把未处理数据(棕红色)和写入数据(蓝色)按顺序复制到新的缓冲区内,并调整好Read和Write指针的位置。最后释放掉原来的缓冲区。

我们可以看到,经过这样一个过程,我们的缓冲区,将在Read指针处理速度较慢并在处理信息量增大时,逐渐扩容。但是,当扩容到一定程度,将达到一个平衡。因为信息量不可能无限增大,当需处理信息量达到最大值再结合Read指针的不断处理,缓冲区的大小也将稳定下来。

我们一开头就给此缓冲区命名为‘环形队列’。从以上的图和文字,我们可以形象的理解:由于缓冲区大小最终将稳定,Write和Read指针将无障碍的在缓冲区中不断循环回滚,其运行轨迹,将是一个环形。

分享到:
评论

相关推荐

    使用Netty解决TCP粘包和拆包问题过程详解

    使用Netty解决TCP粘包和拆包问题过程详解 Netty是一个流行的Java网络编程框架,提供了简洁、灵活的API来处理网络编程的各种问题。其中,解决TCP粘包和拆包问题是Netty的一个重要应用场景。本文将详细介绍使用Netty...

    C#中TCP粘包问题的解决方法

    解决TCP粘包问题通常有以下几种策略: 1. 包头包尾法:在每个数据包的开始和结束位置添加特定的包头和包尾。包头通常包含包体的长度信息,这样接收方可以根据包头确定包体的长度,从而正确拆分数据包。例如,在C#...

    【QT】自定义协议解决TCP粘包和拆包问题

    在某些需要精确控制数据传输的应用中,如游戏、实时通信等,解决TCP粘包和拆包问题是至关重要的。QT是一个跨平台的C++图形用户界面应用程序开发框架,它提供了丰富的网络编程接口,可以用来处理这个问题。 本文将...

    详细演示如何优雅处理TCP粘包C++源代码 包含完整项目资源确保可顺利编译运行

    本程序使用设计良好的函数,使得应用层不需要考虑网络消息是如何被接受和发送的,重点演示了如何优雅地处理TCP/IP网络数据粘包和丢包的刺手问题,你只要调用相应的函数就可以了。你只需要定义自己的协议头和消息...

    c#tcp 粘包拆包解决方法,包头加数据长度

    发生TCP粘包或拆包有很多原因,现列出常见的几点,可能不全面,欢迎补充, 1、要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。 2、待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。 3、...

    tcp 粘包 拆包解决思路以代码

    为了解决TCP粘包和拆包的问题,通常有以下几种策略: 1. **包头+包体**:这是最常用的方法,也是题目中提到的“包长+内容缓冲区”组织方法。每个数据包前都加上一个包头,包头中包含该数据包的实际长度,这样接收方...

    TCP 粘包解决办法

    通过以上步骤,可以有效地解决TCP粘包问题,确保数据的正确传输与接收。 ### 总结 TCP粘包问题是网络通信开发中常见的问题之一,通过合理的封包和拆包策略可以有效避免粘包带来的数据解析错误。在实际应用中,开发...

    Golang TCP粘包拆包问题的解决方法

    ### Golang TCP粘包拆包问题的解决方法 #### 一、引言 在使用Go语言进行网络编程时,特别是TCP编程过程中,经常会遇到所谓的“粘包”与“拆包”问题。这些问题的发生通常会影响到数据的正确性以及系统的稳定性。...

    C# TCP粘包解决

    然而,TCP在处理数据传输时,可能会出现“粘包”现象,这是开发者需要理解和解决的一个关键问题。 粘包是指在一个TCP连接中,发送方发送的多个数据包在接收方可能被合并成一个大的数据包进行接收,或者接收方可能将...

    Socket通信,通过异步,解决粘包问题

    不过,这并不能完全解决问题,因为数据包的合并与拆分是TCP协议栈内部的行为,不受应用层控制。 2. **固定长度报文**:在设计通信协议时,约定每个报文都有固定的长度。接收方在接收到数据后,根据预设的报文长度...

    unity实现Socket通讯(内含tcp粘包/拆包解决)

    本教程将深入探讨如何在Unity中实现Socket通信,包括TCP连接、粘包/拆包问题的解决方案。 一、TCP连接基础 TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在Unity中...

    Socket编程TCP粘包Demo.zip

    解决TCP粘包问题通常有以下几种方法: 1. **设置合适的缓冲区大小**:根据预期的数据包大小,合理设定接收缓冲区的大小,避免一次接收过多的数据导致粘包。 2. **分包与解包策略**:在数据包设计时,添加特定的...

    C#实现Socket编程 (异步通讯,解决Tcp粘包)第三阶段

    本文将深入探讨如何使用C#语言来实现Socket编程,特别是在处理异步通信和解决TCP粘包问题的第三阶段。C#提供了丰富的类库支持网络编程,使得开发者能够方便地构建基于TCP/IP的客户端和服务器应用。 首先,让我们...

    Boostasio异步TCP通讯及tcp粘包解包解决方案.doc

    "Boostasio异步TCP通讯及tcp粘包解包解决方案" Boostasio异步TCP通讯是基于 Boost Asio 库实现的异步 TCP 通讯机制,...同时,我们还讨论了 TCP 粘包解包问题的解决方法,并提供了一个使用标记字段方法的示例代码。

    Socket编程TCP粘包问题及解决方案.docx

    ### Socket编程TCP粘包问题及解决方案 #### 一、TCP粘包问题概述 TCP作为一种可靠的面向连接的传输层协议,提供了基于字节流的服务。在TCP传输过程中,发送方发送的数据被视为连续不断的字节流,而不是离散的消息...

    TCP粘包问题浅析及其解决方案.docx

    TCP 粘包问题浅析及其解决方案 TCP(Transmission Control Protocol)是一种面向连接的运输层协议,在使用 TCP 协议之前,必须先建立 TCP 连接,即三次握手。在数据传输完毕之后,必须释放已经建立的 TCP 连接,...

    TCP粘包简单处理类

    总的来说,TCP粘包问题可以通过设计合理的报文结构和解析策略来解决。`Packet`类的实现和使用示例展示了如何在实际编程中应对这一挑战。只要正确地处理数据包的头部和数据体,就能确保TCP通信的可靠性和有效性。

Global site tag (gtag.js) - Google Analytics