1

对于网络应用程序,我们传输动态数据的方式是通过 memcpying 一个结构到 (void*) 中。这会带来一些问题,例如对 std::string 执行此操作时。字符串可以是动态长度的,那么对方怎么知道字符串什么时候结束呢?我的一个想法是使用类似于 Java 的 DataOuputStream 的东西,在那里我可以将任何变量传递给它,然后可以将其放入 (void*) 中。如果这不能完成,那么它很酷。我只是不太喜欢 memcpying 结构。关于它的某些东西似乎不太对劲。

谢谢,
罗比

4

3 回答 3

1

结构上的 memcpy 没有任何问题 - 因为结构充满了固定大小的缓冲区。在其中放置一个动态变量,您必须以不同的方式对其进行序列化。

如果您有一个带有 std::strings 的结构,请创建一个流运算符并使用它来格式化缓冲区。然后,您可以将该缓冲区 memcpy 到数据传输中。如果您有 boost,请使用Boost::serialize为您完成所有这些工作(该链接还包含指向替代序列化库的链接)

注意:传递可变大小缓冲区的通常方法是先发送长度,然后发送那么多字节的数据。有时您会看到在收到分隔符之前传输的数据(并且该数据中的字段由另一个字符分隔,例如逗号)。

于 2009-08-11T12:48:32.210 回答
0

我看到这个问题的两个部分: - 通过网络序列化数据 - 如何将结构传递到网络堆栈

要通过网络序列化数据,您需要一个协议。不一定很难;对于 ASCII,即使是 cr/lf 作为数据包结束也可以这样做。如果您使用框架(如 MFC),它可能会为您提供序列化功能;在这种情况下,您需要担心如何以数据包的形式发送它。通常对我很有效的打包是:

<length><data_type>[data....][checksum]

在这种情况下,校验和是可选的,并且零数据也是可能的,例如,如果信号是在 data_type 中携带的(即用于确认的 Ack)

如果您正在使用结构处理 memcpy,则需要考虑 memcpy 仅制作浅拷贝。指针一旦通过网络传输就毫无价值;例如,您应该从该指针传输数据(即您的字符串示例的内容)

于 2009-08-11T13:26:49.093 回答
0

要通过网络发送动态数据,您有以下选项。

同一个数据包中的第一个选项。

void SendData()
{
   int size;
   char payload[256];

   Send(messageType)
   Send(size);
   Send(payload)
}

第二种选择:

void SendData()
{
   char payload[256];

   Send(messageType)
   Send(payload)
}

尽管在任何一种情况下,您都将面临更多的设计选择。在第一个示例中,您将发送消息类型、有效负载大小以及有效负载。

您拥有的第二个选项是您可以发送消息类型,然后您可以发送具有空终止符分隔符的字符串。

尽管这两种选择都不能完全涵盖我认为您面临的问题。首先,您需要确定您是否正在构建游戏,您将使用哪种类型的协议,UDP?TCP?您将面临的第二个问题是最大数据包大小。然后最重要的是,您需要有适当的框架,以便您可以计算不会碎片化和丢失到互联网的最佳数据包大小。之后,您就可以在客户端和服务器之间传输和接收多少数据进行带宽控制。

例如,大多数游戏处理这种情况的方式是每个数据包都用以下标识。

MessageType
MessageSize
CRCCheckSum
MessageID
void buffer[payload]

在您需要发送动态数据的情况下,您将发送一系列数据包而不仅仅是一个。例如,如果您要通过网络发送文件,最好的选择是使用 TCP/IP,因为它是一个流式协议,并且它保证完整的流安全地到达另一端。另一方面,UDP 是基于数据包的协议,不检查所有数据包是否按顺序到达或根本不检查另一端。

所以总而言之。

  1. 对于动态数据,发送多个数据包但带有一个特殊标志来表示更多数据将到达以完成此消息。
  2. 保持简单,如果您使用 C++ 不要假设数据包或数据将包含空终止符,如果您决定使用空终止符,请检查与有效负载相比的大小。
于 2009-08-11T13:30:17.933 回答