1

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

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

4

3 回答 3

5

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

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

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

让我们考虑数据包具有以下结构:

[LEN] X X X...

数据的大小在哪里LEN,每个 X 是一个字节。

如果您收到:

4 X X X
[--1--]

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

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

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

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

于 2010-10-02T21:10:13.593 回答
1

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

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

于 2010-10-02T21:11:13.217 回答
1

这通常是通过在消息前面加上一个或两个字节的长度值来完成的,就像你说的,它给出了剩余数据的长度。如果我对您的理解正确,您将其作为纯文本(即“5”、“5”)发送,这可能会被拆分。由于您不知道十进制数的长度,因此它有些模棱两可。如果您绝对需要使用纯文本,也许您可​​以将长度编码为 16 位十六进制值,即:

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

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


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

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

于 2010-10-02T21:14:33.947 回答