代码之家  ›  专栏  ›  技术社区  ›  DigitalZebra

通过BoostTCP发送大数据块?

  •  4
  • DigitalZebra  · 技术社区  · 15 年前

    我必须通过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是否有任何东西可以将这一点抽象化。

    4 回复  |  直到 8 年前
        1
  •  2
  •   teeks99    8 年前

    你试过用Boost的TCP吗?我不明白为什么2MB会成为一个需要转移的问题。我假设我们谈论的是一个以100Mbps或1Gbps速度运行的局域网,一台拥有大量RAM的计算机,而且不必有超过20毫秒的响应时间?如果您的目标是从一台计算机到另一台计算机,只需发送它,TCP将为您处理分块。

    我有一个用boost编写的TCP延迟检查工具,它尝试发送各种大小的缓冲区,我经常检查高达20MB的缓冲区,这些缓冲区似乎可以顺利通过。

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

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

    现在我手头有几分钟时间了,我仔细检查了一下,并快速地执行了您所说的内容: https://github.com/teeks99/data-chunker 有三大部分:

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

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

    接收器-等待来自发送方的连接,并解压缩其接收的数据。

    我在zip中包含了.exe,运行sender.exe/receiver.exe--help查看选项,或者只查看main。

    更详细的解释: 打开两个命令提示,并在这两个提示中转到datachunker\debug。 在其中一个 在另一台计算机中运行sender.exe(可能在其他计算机上,在这种情况下,在可执行文件名后添加--remote host=ip.add.re.ss,如果您想尝试发送多次,并且--num sends=10发送十次)。 查看代码,您可以看到发生了什么,在respecitve main()函数中创建TCP套接字的接收端和发送端。发送方创建了一个新的PrimitiveCollection并用一些示例数据填充它,然后序列化并发送它……接收者将数据反序列化为一个新的PrimitiveCollection,此时,其他人可以使用该Primitive集合,但我只是将其写入控制台。

    编辑: 将示例移动到GitHub。

        2
  •  2
  •   Community CDub    7 年前

    没有任何幻想,从我在网络课上的记忆来看:

    • 向接收器发送一条消息,询问它可以处理多大的数据块
    • 尽可能少地使用它和您自己的发送功能,然后回答说:
      • 你要寄多大尺寸的,要寄多少
    • 收到后,只需发送每个块。你需要等待一个“确定”的回复,这样你就知道你不会浪费时间发送给不在那里的客户。这也是客户发送“我要取消”消息而不是“确定”的好时机。
    • 发送,直到所有数据包都被答复为“确定”
    • 传输数据。

    这是因为TCP保证按顺序交付。UDP需要数据包编号(用于订购)。

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

    举个例子,我能挖掘的只有 this page 而这 old question . 我认为你所做的工作会与 Boost.Serialization .

        3
  •  2
  •   Sergey Kurenkov    15 年前

    为了在一定程度上提高套接字性能,我想再增加一点考虑设置TCP套接字缓冲区大小。

    有一个公用事业 Iperf 这样可以测试TCP套接字上的交换速度。我在Windows上运行了一些测试,在100mbs局域网中。对于8kb默认TCP窗口大小,速度为89 Mbits/sec,对于64kb TCP窗口大小,速度为94 Mbits/sec。

        4
  •  -1
  •   divegeek    15 年前

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

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

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

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

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

    我建议您使用JSON。2MB不是很多数据,所以生成和解析的开销不会很大,您可以在JSON中直接表示您的数据结构。生成的文本将是自定界的、可读的、易于流式处理的,并且易于解析回目标端的内存中。