对于网络应用程序,我们传输动态数据的方式是通过 memcpying 一个结构到 (void*) 中。这会带来一些问题,例如对 std::string 执行此操作时。字符串可以是动态长度的,那么对方怎么知道字符串什么时候结束呢?我的一个想法是使用类似于 Java 的 DataOuputStream 的东西,在那里我可以将任何变量传递给它,然后可以将其放入 (void*) 中。如果这不能完成,那么它很酷。我只是不太喜欢 memcpying 结构。关于它的某些东西似乎不太对劲。
谢谢,
罗比
结构上的 memcpy 没有任何问题 - 因为结构充满了固定大小的缓冲区。在其中放置一个动态变量,您必须以不同的方式对其进行序列化。
如果您有一个带有 std::strings 的结构,请创建一个流运算符并使用它来格式化缓冲区。然后,您可以将该缓冲区 memcpy 到数据传输中。如果您有 boost,请使用Boost::serialize为您完成所有这些工作(该链接还包含指向替代序列化库的链接)
注意:传递可变大小缓冲区的通常方法是先发送长度,然后发送那么多字节的数据。有时您会看到在收到分隔符之前传输的数据(并且该数据中的字段由另一个字符分隔,例如逗号)。
我看到这个问题的两个部分: - 通过网络序列化数据 - 如何将结构传递到网络堆栈
要通过网络序列化数据,您需要一个协议。不一定很难;对于 ASCII,即使是 cr/lf 作为数据包结束也可以这样做。如果您使用框架(如 MFC),它可能会为您提供序列化功能;在这种情况下,您需要担心如何以数据包的形式发送它。通常对我很有效的打包是:
<length><data_type>[data....][checksum]
在这种情况下,校验和是可选的,并且零数据也是可能的,例如,如果信号是在 data_type 中携带的(即用于确认的 Ack)
如果您正在使用结构处理 memcpy,则需要考虑 memcpy 仅制作浅拷贝。指针一旦通过网络传输就毫无价值;例如,您应该从该指针传输数据(即您的字符串示例的内容)
要通过网络发送动态数据,您有以下选项。
同一个数据包中的第一个选项。
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 是基于数据包的协议,不检查所有数据包是否按顺序到达或根本不检查另一端。
所以总而言之。