通过Boost TCP发送大块数据?

4
我需要通过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… 更准确地说,这是将数据分块并发送的问题。尽管如此,我仍然很想知道 Boost 是否具有可以在某种程度上抽象化此问题的工具。

2
无论您使用哪个API,一种简单的方法是首先发送一个小的4字节头部,描述数据集的大小,然后继续发送数据直到完成。实际上没有限制。根据您的计算需求,您还可以在发送之前压缩数据。很多事情取决于具体的问题。 - BobbyShaftoe
4个回答

3

你尝试过使用Boost的TCP吗?我不认为2MB会成为传输问题。 我假设我们正在运行100mbps或1gbps的局域网,有足够的RAM的计算机,并且不必具有20ms以上的响应时间吗?如果您的目标只是从一台计算机将所有2MB发送到另一台计算机,请直接发送它,TCP将帮助您进行分块处理。

我编写了一个使用Boost编写的TCP延迟检测工具,该工具尝试发送各种大小的缓冲区,我通常检查最多20MB,这些似乎没有任何问题。

我想说的是,在您确定存在问题之前,请不要花费时间开发解决方案 :-)

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

现在我有几分钟空闲时间,我浏览了一下并快速实现了您谈论的内容:https://github.com/teeks99/data-chunker 其中有三个重要组成部分:

序列化程序/反序列化程序,Boost有自己的程序,但与自己编写的程序相比并没有更好,因此我自己编写了程序。

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

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

我已将.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工具...似乎没有太多有效使用它的示例。 - Polaris878
下载链接已损坏 - 请您添加一个新的链接。 - Del Pedro
@teeks99,你还有这个例子吗?如果你能更新一下死链接就太好了,谢谢。 - Katu
@Katu,我已经更新了上面的链接,现在你应该能够获取代码了。 - teeks99

2

只凭我在网络课上所记的,简单讲述:

  • 向接收者发送一条消息,询问其能够处理多大数据块尺寸
  • 取该值与你自己的发送能力的最小值,并回复说:
    • 你将发送多大的尺寸,将发送多少个
  • 在获得这些信息之后,只需发送每个数据块。你需要等待一个“Ok”回应,这样你就知道你没有浪费时间发送给不在那里的客户端。这也是客户端发送“我要取消”的信息而不是“Ok”的好时机。
  • 发送,直到所有数据包都得到了“Ok”回复。
  • 数据就被传输了。

这是因为TCP保证有序传递。UDP需要数据包编号(用于排序)。

压缩相同,除了你发送压缩数据。 (数据就是数据,这完全取决于你如何解释它)。只需确保您通信了数据如何进行压缩 :)

至于示例,我能找到的仅有这个页面和这个旧的问题。我认为你所做的工作与Boost.Serialization结合使用效果会很好。


2

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

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


-1
除了如何分块和传递数据之外,您还应该考虑平台差异。如果两台计算机是相同的架构,并且两边运行的代码是相同编译器的同一版本,则可以将原始内存结构直接传输到网络另一侧并让其工作。但是,如果不是所有东西都相同,则可能会遇到字节序、结构填充、字段对齐等问题。
通常来说,最好为数据单独定义一个网络格式而不是采用内存表示。该格式可以是二进制格式,在此情况下,数值应转换为标准形式(主要是将字节序更改为“网络顺序”,即大端模式),或者可以是文本格式。许多网络协议选择文本格式,因为它消除了许多格式问题,并且使调试更加容易。个人而言,我非常喜欢 JSON。它不太冗长,每种编程语言都有很好的库可用,并且人类读写起来也非常容易理解。
定义网络协议时需要考虑的一个关键问题是接收方如何知道何时接收到了所有数据。有两种基本方法。首先,您可以在消息开头发送显式大小,然后接收方知道要继续读取直到获取那么多字节。另一种方法是使用某种消息结束分隔符。后者的优点是您不必事先知道要发送多少字节,但缺点是您必须想出如何确保消息结束分隔符不会出现在消息中。
一旦您决定数据在网络上流动时应该如何结构化,那么您应该想出一种将内部表示转换为该格式的方法,最好是以“流”方式,这样您就可以循环遍历数据结构,将其每个部分转换为网络格式并将其写入网络套接字。
在接收端,您只需反向执行该过程,将网络格式解码为适当的内存格式。

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


哇,这里有很多信息。我本来想给你点赞的,因为你建议将协议序列化与内存表示分离,但是......为什么要使用JSON来处理大量科学数据呢?不行,伙计。 - Tom
对于2 MB的数据,没有必要做其他的事情。即使它扩展到5或6 MB,又怎样呢?传输它仍然只需要极短的时间。使用JSON比搞二进制格式更容易、更安全。在许多情况下,通过压缩/解压缩管道传输的大小会比二进制格式更小。如果我们谈论大量的数据,我会给出非常不同的答案,但对于这个问题,让它变得简单。 - divegeek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接