将缓冲区复制到结构时缺少数据
Missing data while copying buffer to struct
我有一个接收 16 字节请求消息的 TCP 服务器套接字。请求消息将有几个字段,根据字段值,我需要继续执行不同的操作。
当我尝试将缓冲区复制到结构时,我可以看到丢失的数据。我尝试了所有可能的方法,但无法弄清楚我是否需要进行结构填充。
我的结构看起来像,
struct stRequestMsg {
uint16_t startTag;
uint32_t messageSize;
uint16_t messageID;
uint16_t sequenceNumber;
uint16_t messageType;
uint32_t reserved;
};
我所做的只是,
char buff[1024]
result = static_cast<int>(recv(sockDesc, buff, sizeof(stRequestMsg), 0));
if (0 < result) {
printf("n Actual value on buffer");
for (int i = 0; i < result; i++)
{
printf("n buff[%d] = 0x%x", i,buff[i]);
}
reqMessage = *(stRequestMsg *)buff;
printf("n RESULT of reqMessage = *(stRequestMsg *)buff;");
printf("nstartTag : 0x%x", reqMessage.startTag);
printf("nmessageSize : 0x%x", reqMessage.messageSize);
printf("nmessageID : 0x%x", reqMessage.messageID);
printf("nsequenceNumber : 0x%x", reqMessage.sequenceNumber);
printf("nmessageType : 0x%x", reqMessage.messageType);
printf("nreserved : 0x%x", reqMessage.reserved);
stRequestMsg hdr;
std::copy(&hdr, &hdr + 1, reinterpret_cast<stRequestMsg*>(buff));
printf("n RESULT of std::copy(&hdr, &hdr + 1, reinterpret_cast<stRequestMsg*>(buff));");
printf("nstartTag : 0x%x", reqMessage.startTag);
printf("nmessageSize : 0x%x", reqMessage.messageSize);
printf("nmessageID : 0x%x", reqMessage.messageID);
printf("nsequenceNumber : 0x%x", reqMessage.sequenceNumber);
printf("nmessageType : 0x%x", reqMessage.messageType);
printf("nreserved : 0x%x", reqMessage.reserved);
memcpy(&reqMessage, buff, sizeof(stRequestMsg));
printf("n RESULT of std::copy(&hdr, &hdr + 1, reinterpret_cast<stRequestMsg*>(buff));");
printf("nstartTag : 0x%x", reqMessage.startTag);
printf("nmessageSize : 0x%x", reqMessage.messageSize);
printf("nmessageID : 0x%x", reqMessage.messageID);
printf("nsequenceNumber : 0x%x", reqMessage.sequenceNumber);
printf("nmessageType : 0x%x", reqMessage.messageType);
printf("nreserved : 0x%x", reqMessage.reserved);
reqMessage = *reinterpret_cast<stRequestMsg*>(buff);
printf("n RESULT of reqMessage = *reinterpret_cast<stRequestMsg*>(buff);");
printf("nstartTag : 0x%x", reqMessage.startTag);
printf("nmessageSize : 0x%x", reqMessage.messageSize);
printf("nmessageID : 0x%x", reqMessage.messageID);
printf("nsequenceNumber : 0x%x", reqMessage.sequenceNumber);
printf("nmessageType : 0x%x", reqMessage.messageType);
printf("nreserved : 0x%x", reqMessage.reserved);
}
我可以看到buff
上收到的值是正确的,但是当我尝试将整个缓冲区映射到结构时,我可以看到丢失的数据。我相信解决方案可能很简单,但我不知道问题出在哪里。
输出如下所示,
Actual value on buffer
buff[0] = 0x50
buff[1] = 0x0
buff[2] = 0x1e
buff[3] = 0x0
buff[4] = 0x0
buff[5] = 0x0
buff[6] = 0x31
buff[7] = 0x0
buff[8] = 0x1
buff[9] = 0x0
buff[10] = 0x2
buff[11] = 0x0
buff[12] = 0x1
buff[13] = 0x0
buff[14] = 0x0
buff[15] = 0x0
RESULT of reqMessage = *(stRequestMsg *)buff;
startTag : 0x50
messageSize : 0x310000
messageID : 0x1
sequenceNumber : 0x2
messageType : 0x1
reserved : 0x8a5c6da
RESULT of std::copy(&hdr, &hdr + 1, reinterpret_cast<stRequestMsg*>(buff));
startTag : 0x50
messageSize : 0x310000
messageID : 0x1
sequenceNumber : 0x2
messageType : 0x1
reserved : 0x8a5c6da
RESULT of memcpy(&reqMessage, buff, sizeof(stRequestMsg));
startTag : 0xf7ec
messageSize : 0x1e0050
messageID : 0x0
sequenceNumber : 0x31
messageType : 0x1
reserved : 0x1
RESULT of reqMessage = *reinterpret_cast<stRequestMsg*>(buff);
startTag : 0xf7ec
messageSize : 0x1e0050
messageID : 0x0
sequenceNumber : 0x31
messageType : 0x1
reserved : 0x1
但我所期望的是
startTag = 0x5000;
messageSize = 0x1E000000;
messageID = 0x3100;
sequenceNumber = 0x100;
messageType = 0x200;
reserved = 0x1000000;
编辑:我尝试更改消息大小的可变大小,并保留为uint16_t,通过这样做memcpy
我收到了所有正确的信息。
50 00 1E 00 00 00 31 00 01 00 02 00 01 00 00 00
如果我们相信您的第一个输出,那么这就是缓冲区中的内容。
struct stRequestMsg {
uint16_t startTag;
uint32_t messageSize;
uint16_t messageID;
uint16_t sequenceNumber;
uint16_t messageType;
uint32_t reserved;
};
您似乎假设此结构定义像这样映射到内存上:
50 00|1E 00 00 00|31 00|01 00|02 00|01 00 00 00
start|messagesize|msgID|seqNm|msgTp|reserved...
事实并非如此,在您的特定情况下,它是
50 00|1E 00|00 00 31 00|01 00|02 00|01 00|00 00|GG GG GG GG
start|xx xx|messagesize|msgID|seqNm|msgTp|xx xx|reserved...
其中GG
表示垃圾(因为它在缓冲区之外(。结构在内存中这样布局的原因是结构填充:结构字段根据其对齐要求在内存中布局。对于int
(可能uint32_t
(,这通常是 4 个字节,这意味着这样的成员只会从 4 的倍数的偏移量开始。为了实现这一点,编译器插入填充。因此,您的结构实际上如下所示:
struct stRequestMsg {
uint16_t startTag;
char xxxxPad1[2];
uint32_t messageSize;
uint16_t messageID;
uint16_t sequenceNumber;
uint16_t messageType;
char xxxxPad2[2];
uint32_t reserved;
};
您遇到的另一个问题是字节顺序:您的系统似乎使用小端序,而来自网络的数据以大端序(这也是网络字节顺序,所以这是一件好事(出现。
这就是为什么startTag == 0x0050
而不是0x5000
.作为小端序,您的系统假定第一个字节容纳最低位,而不是最高位。
要做到这一点,您应该查找一些有关序列化和反序列化的资源......
反序列化示例(在 C 语言中,但应该很容易调整到C++。抱歉,写作时没有注意标签,我看到了一个printf
,只是假设 C :D(:
#include <stdio.h>
#include <stdint.h>
struct stRequestMsg {
uint16_t startTag;
uint32_t messageSize;
uint16_t messageID;
uint16_t sequenceNumber;
uint16_t messageType;
uint32_t reserved;
};
void printIt(struct stRequestMsg m) {
printf("{n"
" .startTag = %#x;n"
" .messageSize = %#x;n"
" .messageID = %#x;n"
" .sequenceNumber = %#x;n"
" .messageType = %#x;n"
" .reserved = %#x;n"
"}n",
m.startTag, m.messageSize, m.messageID,
m.sequenceNumber, m.messageType, m.reserved);
}
uint16_t deserialize_uint16(char const * const b) {
return ((uint16_t) b[0] << 8u) |
((uint16_t) b[1]);
}
uint32_t deserialize_uint32(char const * const b) {
return ((uint16_t) b[0] << 24u) |
((uint16_t) b[1] << 16u) |
((uint16_t) b[2] << 8u) |
((uint16_t) b[3]);
}
struct stRequestMsg deserialize(char const * const b) {
struct stRequestMsg r;
r.startTag = deserialize_uint16(b);
r.messageSize = deserialize_uint32(b + 2);
r.messageID = deserialize_uint16(b + 6);
r.sequenceNumber = deserialize_uint16(b + 8);
r.messageType = deserialize_uint16(b + 10);
r.reserved = deserialize_uint32(b + 12);
return r;
}
int main(void) {
char buff[16];
buff[0] = 0x50; buff[1] = 0x00;
buff[2] = 0x1E; buff[3] = 0x00;
buff[4] = 0x00; buff[5] = 0x00;
buff[6] = 0x31; buff[7] = 0x00;
buff[8] = 0x10; buff[9] = 0x00;
buff[10] = 0x20; buff[11] = 0x00;
buff[12] = 0x10; buff[13] = 0x00;
buff[14] = 0x00; buff[15] = 0x00;
struct stRequestMsg msg = deserialize(&(buff[0]));
printIt(msg);
return 0;
}
(活在 ideone 上(
- 链表,反向函数,数据结构
- 如何使用set实现无序数据结构?
- 我们可以将数据永久保存为数据结构吗?
- C++中的可变长度数组/数据结构
- 用于存储由空格分隔的字符串的 C++/C 数据结构
- 通过 NIF 从C++返回自定义数据结构
- 编译器上的策略数据结构不起作用
- 尝试构建"lock-free"数据结构C++
- 设计将引用元素移动到开头的数据结构.C++
- 在学习数据结构之前对STL有一个了解是好的吗?
- 如何解析表示树状数据结构的字符串
- 我对数据结构、双向链表有一些问题
- googletest:测试太大的数据结构
- C++中deque数据结构的大O是什么?
- 我可以使用哪种数据结构来处理这种方式
- 将文本文件解析为树状数据结构
- C++ 中具有 O(1) 搜索时间复杂度的数据结构
- 哪些存储了不完整类型的 STL 数据结构可以用作类成员?
- C++,您能否设计一种数据结构,将指针保存在连续内存中并且不会使它们失效?
- 带参数的数据结构的全局声明