【发布时间】:2014-07-30 01:15:50
【问题描述】:
我正在尝试发送带有固定长度标头的数据,该标头告诉服务器在读取数据之前必须读取多少字节的数据。不过,我在这样做时遇到了麻烦。我希望一次能够发送的最大数据字节数是 65536,所以我发送一个 uint16_t 类型变量作为我的数据的标头,因为它可以表示的最大数量是 65536。
问题是,uint16_t 占用两个字节,而小于 255 的数字只占用一个字节。所以我在客户端有这段代码:
uint16_t messageSize = clientSendBuf.size(); //clientSendBuf is the data I want to send
char *bytes((char*)&messageSize);
clientSendBuf.prepend(bytes);
client.write(clientSendBuf);
在服务器上,我处理接收这样的消息:
char serverReceiveBuf[65536];
uint16_t messageSize;
client->read((char*)&messageSize, sizeof(uint16_t));
client->read(serverReceiveBuf, messageSize);
我稍后会改变这个,因为它不是最好的解决方案(特别是当所有数据都不可用时),但我想先解决这个问题。我的问题是,当clientSendBuf.size() 太小(在我的测试用例中是 16 个字节,我假设每个低于 255 的值都会发生这种情况)使用
client->read((char*)&messageSize, sizeof(uint16_t));
读取不属于标头的第二个字节,为messageSize 提供不正确的值并导致服务器崩溃。如果我将sizeof(uint16_t) 替换为1,那么服务器会按照我的预期正常读取数据,尽管那时我的messageSize 最大值为255,这比我想要的要低得多。如何使messageSize 前面的clientSendBuf 始终是两个字节,即使对于数字
【问题讨论】:
-
为什么即使发送缓冲区很小,标题 still 也不是 16 位(两个字节)?即使您只有一个字节的数据要发送,那么您应该仍然发送两个字节的固定标头。
-
@JoachimPileborg 你告诉我。我也是这么想的,但是当我发送一个小的
messageSize(并通过调试检查)时,服务器端messageSize的值与客户端发送的messageSize不一样。此外,serverReceiveBuf中的数据与发送的数据不匹配,相差一个字节(第一个字节是我期望的第二个字节)。当我将sizeof(uint16_t)更改为1时,一切都很好,但我被限制为255 个字节,这还不够好。我的问题是如何确保标题总是两个字节,即使messageSize需要一个 -
还请考虑endianess issues,当您以这种方式在客户端和服务器之间交换数字数据时可能会发生这种情况。我建议将
uint16_t值始终转换为网络字节顺序(即大端)。 -
那你需要先看看
prepend函数是做什么的,是不是只加了一个一个字节?我对此表示怀疑,因为它不需要添加多个字节。接下来,您可能想看看write函数的作用。 -
@JoachimPileborg 无论数据需要多少字节,它都会预先添加。所以当我使用
char *bytes((char*)&messageSize);并且messageSize*bytes 只需要一个字节来存储,这就是前面的所有内容。我还能如何发送固定长度的标头?