处理TCP流

时间:2010-10-02 20:58:14

标签: c++ client tcp c++builder-5

我们的服务器看似基于数据包。它是来自旧的基于串行的系统的改编。多年来,它已被添加,修改,重建等。由于TCP是流协议而不是数据包协议,因此有时数据包会被分解。 ServerSocket的设计方式是,当客户端发送数据时,部分数据包含消息的大小,例如55。有时这些数据包被分成多个部分。它们按顺序到达但由于我们不知道如何拆分消息,我们的服务器有时不知道如何识别拆分消息。

所以,给了你背景信息。如果数据包被分裂,重建数据包的最佳方法是什么?我们正在使用C ++ Builder 5(是的,我知道,旧的IDE,但这是我们现在可以使用的全部内容。很多工作要在.NET或更新的技术中重新设计)。

3 个答案:

答案 0 :(得分:4)

TCP保证数据按照发送的顺序到达。

该说,您可以将所有传入的数据附加到缓冲区。然后检查您的缓冲区是否包含一个或多个数据包,并将其从缓冲区中删除,将所有剩余数据保留在缓冲区中以供将来检查。

当然,这假设您的数据包有一些标题,表示以下数据的大小。

让我们认为数据包具有以下结构:

[LEN] X X X...

其中LEN是数据的大小,每个X都是一个字节。

如果收到:

4 X X X
[--1--]

数据包未完成,您可以将其保留在缓冲区中。然后,其他数据到达,您只需将其附加到缓冲区:

4 X X X X 3 X X X
        [---2---]

然后,您可以轻松解析2条完整的消息。

如果您这样做,请不要忘记以独立于主持人的形式发送任何长度(ntohsntohl可以提供帮助)。

答案 1 :(得分:1)

我会有一个名为readBytes的函数或带有缓冲区和长度参数的函数,并读取直到读取了很多字节。您需要捕获实际读取的字节数,如果它小于您期望的数字,请前进缓冲区指针并阅读其余部分。继续循环,直到你全部阅读。

然后对标题(包含长度)调用此函数一次,假设标题是固定长度。获得实际数据的长度后,再次调用此函数。

答案 2 :(得分:1)

这通常通过在消息前加上一个或两个字节的长度值来实现,就像你说的那样,它给出了剩余数据的长度。如果我已经正确地理解了你,那么你将它作为纯文本发送(即'5','5'),这可能会被分开。由于您不知道十进制数的长度,因此它有些含糊不清。如果您绝对需要使用纯文本,也许您可​​以将长度编码为16位十六进制值,即:

00ff< 255字节数据> 000a< 10字节数据>

这样,size header的长度固定为4个字节,可以在socket上接收时用作最小读取长度。


编辑:也许我误解了 - 如果读取长度值不是问题,则通过将传入数据连接到字符串,字节缓冲区或其他任何内容来处理拆分,直到其长度等于您在开头读取的值。 TCP将负责其余部分。

如果客户端没有发送完整的消息,请采取额外的预防措施,以确保您不会陷入阻塞读取状态。例如,假设您收到长度标头,并启动一个循环,通过阻止recv()调用继续读取,直到填充缓冲区。如果恶意客户端故意停止发送数据,则在客户端断开连接或开始发送之前,您的服务器可能会被锁定。