【问题标题】:Handling TCP Streams处理 TCP 流
【发布时间】:2011-04-20 08:04:59
【问题描述】:

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

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

【问题讨论】:

  • 你说发送方包含了消息的大小,服务器不知道如何识别拆分消息。它是哪一个?如果你有大小,那么识别分割点很容易。
  • @Ben:是的,看起来就是这样。我问的主要是因为我试图说服其他工程师(服务器软件)他做错了。
  • 如果服务器无法拆分消息,尽管每个消息都有长度,那他就错了。

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


【解决方案1】:

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

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

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

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

[LEN] X X X...

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

如果您收到:

4 X X X
[--1--]

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

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

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

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

【讨论】:

    【解决方案2】:

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

    00ff 000a

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


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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2013-12-14
        • 2014-06-24
        • 2015-02-26
        • 2011-10-06
        • 2016-10-13
        • 1970-01-01
        • 2018-11-04
        • 2013-09-05
        • 1970-01-01
        相关资源
        最近更新 更多