MrDuk
MrDuk

Reputation: 18322

Trouble with packing / unpacking ints to and from char*

I have the following code, which transmits a char* across a UDP socket to a receiver:

struct Packet
{
   int seqNum;
   int ackNum;  
   int payloadSize;
   char* payload;
};
--------------------------------------
//MTU = 1460
char* payload = (char*)malloc(MTU);
int bytesCopied = sprintf(payload, "%d%d%d", dataIt->second.seqNum, dataIt->second.ackNum, dataIt->second.payloadSize);
cout << "Bytes Copied: " << bytesCopied << endl;  // prints 3 - thought it would print 12 (3*sizeof(int))?
strcat(payload, dataIt->second.payload);
bytesSent = sendto(mySocket, payload, packetSize, 0,
            (const struct sockaddr *)&toNode,length);

The receiver looks like:

int n;
char buffer[MTU];
bzero(buffer, MTU);
unsigned int length = sizeof(struct sockaddr_in);
struct sockaddr_in from;

n = recvfrom(mySocket,buffer,MTU,0,(struct sockaddr *)&from, &length);

if (n < 0) 
    perror("recvfrom");
else
{
    char* seqNum = (char*)malloc(sizeof(int));
    memcpy(seqNum, &buffer, sizeof(int));
    cout << "SeqNum: " << seqNum << endl;
}

When I attempt to send 5 bytes of payload: 105##### -- the receiver outputs: SeqNum: 105#. When I send: 1010########## (10 bytes of payload) the receiver puts: SeqNum: 1010. What am I doing wrong?

Notes:

Edit:

I've tried to also do:

memcpy(payload, &dataIt->second.seqNum, sizeof(int));
payload += sizeof(int);
memcpy(payload, &dataIt->second.ackNum, sizeof(int));
payload += sizeof(int);
memcpy(payload, &dataIt->second.payloadSize, sizeof(int));
payload += sizeof(int);
strcat(payload, dataIt->second.payload);
payload -= packetSize; //sizeof(dataIt->second.payload) + sizeof(int) + sizeof(int) + sizeof(int)

bytesSent = sendto(mySocket, payload, packetSize, 0,
(const struct sockaddr *)&toNode,length);

But this is wrong, because I'm just corrupting the stream when I run this.

Upvotes: 0

Views: 69

Answers (1)

M.M
M.M

Reputation: 141638

Re. this code:

int bytesCopied = sprintf(payload, "%d%d%d", dataIt->second.seqNum, dataIt->second.ackNum, dataIt->second.payloadSize);
cout << "Bytes Copied: " << bytesCopied << endl;

I don't know why you expected bytesCopied to be 12. sizeof(int) has nothing to do with this; using sprintf("%d" causes the int to be converted to base 10 digits. The length could be anywhere from 3 to 30, or even more if your ints are larger than 32-bit.

If you get the result 3 it indicates that all of those integers were in the range 0 through 9.

This is not a very good data format either, as the other end does not know how to unpack it. Imagine the receiver sees "12345". How does it know whether you sent 12 34 5, or 1 23 45 ?

bytesSent = sendto(mySocket, payload, packetSize, 0, (const struct sockaddr *)&toNode,length);

length and packetSize are not defined anywhere.

char* seqNum = (char*)malloc(sizeof(int));
memcpy(seqNum, &buffer, sizeof(int));
cout << "SeqNum: " << seqNum << endl;

Passing a char * to cout like this means that it expects a null-terminated string. However , (if buffer actually contained a packed int) you are sending it four bytes that do not form a string.

Is this code supposed to unpack the data you wrote in with sprintf? Because if so, it doesn't. You seem very mixed up on the difference between an int, and the base 10 representation of that int.

Upvotes: 1

Related Questions