I have a TCP server socket which receives a 16-byte request message. The request message will have several field and based on the field values i need to proceed with different actions.
When I tried to copy the buffer to struct, I could see missing data. I tried all possible methods but couldn't able to figure out whether I need to do structure padding or not.
My structure looks like,
struct stRequestMsg {
uint16_t startTag;
uint32_t messageSize;
uint16_t messageID;
uint16_t sequenceNumber;
uint16_t messageType;
uint32_t reserved;
};
all I do is,
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);
}
I could see the values that received on the buff
are to be correct, but when i tried to map the whole buffer to struct, I could see missing data. I am sure the solution may be simple, but I don't know where is the problem.
The output looks like,
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
but what I expected is
startTag = 0x5000;
messageSize = 0x1E000000;
messageID = 0x3100;
sequenceNumber = 0x100;
messageType = 0x200;
reserved = 0x1000000;
EDIT: I tried changing the variable size of messageSize and reserved to uint16_t and by doing memcpy
I received all correct.
If we believe your first output, then this is what is in your buffer.
You seem to be assuming that this structure definition maps like so onto memory:
Which is not the case, in your particular situation it's
Where
GG
means garbage (as it's outside of your buffer). The reason the structure is laid out like this in memory is structure padding: Fields of structures are laid out in memory according to their alignment requirements. Forint
(and probablyuint32_t
) that's often 4 Bytes, meaning such a member will only start at an offset that is a multiple of 4. To achieve this the compiler inserts padding. Your structure thus actually looks like:The other issue you're running into is byte order: Your system seems to use little endian, while the data from the network is coming as big endian (which is also the network byte order, so this is a good thing).
That's why
startTag == 0x0050
instead of0x5000
. Being little endian, your system assumes the first byte to hold the lowest bits, not the highest.To get this right you should look up some resources on serialization and deserialization ...
Deserialization example (in C, but should be easily adjustable to C++. Sorry, wasn't paying attention to the tags when writing, I saw a
printf
and just assumed C :D):(Live on ideone)