【问题标题】:Sending large chunks of data over Boost TCP?通过 Boost TCP 发送大块数据?
【发布时间】:2009-10-21 04:40:46
【问题描述】:

我必须通过 TCP 将网格数据从一台计算机发送到另一台计算机……这些网格可能相当大。我很难考虑通过 TCP 发送它们的最佳方式是什么,因为我对网络编程知之甚少。

这是我需要放入缓冲区以通过 TCP 发送的基本类结构:

class PrimitiveCollection
{
    std::vector<Primitive*> primitives;
};

class Primitive 
{
    PRIMTYPES primType; // PRIMTYPES is just an enum with values for fan, strip, etc...
    unsigned int numVertices;
    std::vector<Vertex*> vertices;
};


class Vertex
{
    float X;
    float Y;
    float Z;
    float XNormal;
    float ZNormal;
};

我正在使用 Boost 库和他们的 TCP 东西......它相当容易使用。您可以只填充一个缓冲区并通过 TCP 将其发送出去。
但是,当然这个缓冲区只能这么大,我最多可以发送 2 兆字节的数据。

那么,将上述类结构放入所需的缓冲区并通过网络发送的最佳方法是什么?我还需要在接收端反序列化。

我们将不胜感激。

编辑: 再次阅读本文后,我意识到这确实是一个更普遍的问题,并非 Boost 所特有的......它更多的是分块数据并发送数据的问题。不过,我仍然有兴趣看看 Boost 是否有任何东西可以在某种程度上将其抽象出来。

【问题讨论】:

  • 好吧,不管你使用什么 API,一个简单的方法是先发送一个小的 4 字节 hedaer,描述数据集的大小,然后继续发送数据直到你完成。真的没有限制。您还可以在发送数据之前对其进行压缩,具体取决于您的计算需求。很大程度上取决于特定的问题。

标签: c++ networking boost tcp network-programming


【解决方案1】:

你用 Boost 的 TCP 试过了吗?我不明白为什么 2MB 会成为传输的问题。我假设我们正在谈论以 100mbps 或 1gbps 运行的 LAN,一台具有大量 RAM 的计算机,并且响应时间不必超过 20ms?如果您的目标是将所有 2MB 从一台计算机传送到另一台计算机,只需发送它,TCP 会为您处理分块。

我有一个用 Boost 编写的 TCP 延迟检查工具,它尝试发送各种大小的缓冲区,我经常检查高达 20MB 的缓冲区,而且这些似乎没有问题。

我想我想说的是,除非您知道自己有问题,否则不要花时间开发解决方案 :-)

--------- 解决方案实现--------

现在我已经有几分钟的时间了,我通过并快速实现了你所说的:https://github.com/teeks99/data-chunker 主要分为三个部分:

序列化器/反序列化器,boost 有它自己的,但它并不比滚动你自己的好多少,所以我做到了。

发送方 - 通过 TCP 连接到接收方并发送数据

Receiver - 等待来自发送者的连接并解包它接收到的数据。

我已将 .exe 包含在 zip 中,运行 Sender.exe/Receiver.exe --help 以查看选项,或者只查看 main。

更详细的解释: 打开两个命令提示符,然后在它们中都转到 DataChunker\Debug。 在其中一个中运行 Receiver.exe 在另一台上运行 Sender.exe(可能在另一台计算机上,在这种情况下,如果您想尝试多次发送,请在可执行文件名称后添加 --remote-host=IP.ADD.RE.SS 和 --num -sends=10 发送十次)。 查看代码,您可以看到发生了什么,在各自的 main() 函数中创建 TCP 套接字的接收端和发送端。发送者创建一个新的 PrimitiveCollection 并用一些示例数据填充它,然后序列化并发送它......接收者将数据反序列化为一个新的 PrimitiveCollection,此时原始集合可以被其他人使用,但我只是写了到控制台,它已经完成了。

编辑:将示例移至 github。

【讨论】:

  • 是的,我想我正在尝试尽可能有效地使用 Boost TCP 的东西......似乎没有很多有效使用它的例子。
  • 下载已损坏 - 您可以添加一个新链接
  • @teeks99,你还有例子吗?如果您更新死链接,那就太好了,谢谢。
  • @Katu 我更新了上面的链接,所以你现在应该可以获取代码了。
【解决方案2】:

没有任何花哨的东西,从我记得的网络课:

  • 向接收方发送一条消息,询问它可以处理多大的数据块
  • 尽量少用它和您自己的发送能力,然后回复说:
    • 您将发送什么尺寸,您将发送多少个
  • 收到后,只需发送每个块。您需要等待“Ok”回复,这样您就知道您不会浪费时间向不存在的客户发送邮件。这也是客户发送“我正在取消”消息而不是“Ok”的好时机。
  • 发送直到所有数据包都以“Ok”回复为止
  • 数据已传输。

这是可行的,因为 TCP 保证按顺序交付。 UDP 需要数据包编号(用于排序)。

压缩是相同的,只是您发送的是压缩数据。 (数据就是数据,这完全取决于您如何解释它)。只要确保你传达了数据是如何压缩的:)

举个例子,我能找到的只有this page 和这个old question。我认为你正在做的事情与Boost.Serialization 配合使用会很好。

【讨论】:

    【解决方案3】:

    我想再补充一点需要考虑 - 设置 TCP 套接字缓冲区大小以在一定程度上提高套接字性能。

    有一个实用程序Iperf 可以测试通过 TCP 套接字的交换速度。我在 Windows 上在 100 Mbs LAN 中运行了一些测试。使用 8Kb 默认 TCP 窗口大小,速度为 89 Mbits/sec,使用 64Kb TCP 窗口大小,速度为 94 Mbits/sec。

    【讨论】:

      【解决方案4】:

      除了如何分块和传递数据之外,您应该考虑的另一个问题是平台差异。如果两台计算机具有相同的体系结构,并且在双方运行的代码是相同编译器的相同版本,那么您可能应该能够通过网络转储原始内存结构并让它在另一台上运行边。但是,如果一切都不相同,您可能会遇到字节序、结构填充、字段对齐等问题。

      一般来说,最好将数据的网络格式与内存中的表示分开定义。该格式可以是二进制的,在这种情况下,数值应转换为标准格式(主要是将字节序更改为“网络顺序”,即大字节序),也可以是文本格式。许多网络协议选择文本,因为它消除了许多格式问题,并且使调试更容易。就个人而言,我真的很喜欢 JSON。它并不太冗长,每种编程语言都有很好的库可供使用,而且人类非常容易阅读和理解。

      定义网络协议时要考虑的关键问题之一是接收器如何知道它何时收到了所有数据。有两种基本方法。首先,您可以在消息的开头发送一个明确的大小,然后接收者知道继续阅读,直到它得到那么多字节。另一种是使用某种消息结束分隔符。后者的优点是您不必事先知道要发送多少字节,但缺点是您必须弄清楚如何确保消息结束分隔符不会出现在消息。

      一旦您决定了数据在网络中流动时的结构,那么您应该想办法将内部表示转换为该格式,理想情况下是以“流”的方式,这样您就可以循环遍历您的数据结构,将其每一部分转换为网络格式并写入网络套接字。

      在接收端,您只需反转过程,将网络格式解码为适当的内存格式。

      我对您的情况的建议是使用 JSON。 2 MB 并不是很多数据,因此生成和解析的开销不会很大,并且您可以轻松地直接用 JSON 表示您的数据结构。生成的文本将是自定界的、人类可读的、易于流式传输并且易于解析回目标端的内存。

      【讨论】:

      • 哇,这里有很多信息。我打算赞成你评论将协议序列化与内存中的表示分开,但是...... JSON,对于一大堆科学数据来说是什么?没办法,伙计。
      • 对于 2 MB,做其他任何事情都没有意义。所以它扩展到 5 或 6 MB,那又如何呢?您仍在谈论一小部分时间来传输它。 JSON 比使用二进制格式更容易、更安全。在许多情况下,通过压缩器/解压缩器管道传输将导致比二进制格式更小的传输大小。如果我们谈论的是大量数据,我会给出一个非常不同的答案,但为此,让它变得简单。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-13
      • 2020-12-03
      • 1970-01-01
      • 2014-07-01
      • 2016-04-11
      • 1970-01-01
      相关资源
      最近更新 更多