2

I've been banging my head for the last couple of hours with what seemed to be a very easy task.

My app is communicating with a server over tcpip. The protocol requires that the first 4 bytes of each request be the length of the stream, in reverse order. For example, if the length if 13, I need to supply (decimal) {0,0,0,13}; if it's 300, I need to supply {0,0,44,256}. Then, the actual data follows.

Apparently this is something very straightforward to do in Java, and also in VB (e.g. BitConverter.GetBytes(sendString.Length).Reverse().ToArray()). But in obj-c I just couldn't make it work, I've tried all sorts of conversions between NSString/NSData/NSArray, with no luck.

Thanks in advance!

lucianf
  • 547
  • 7
  • 17
  • 1
    Huh? {0,0,44,256} is not a valid byte sequence (in that 256 isn't a valid byte value). Are you just writing an integer in network order (aka big-endian)? – Adam Rosenfield Jul 16 '12 at 21:59
  • possible duplicate of [How can I reverse the byte order of an NSInteger or NSUInteger in objective-c](http://stackoverflow.com/questions/3830862/how-can-i-reverse-the-byte-order-of-an-nsinteger-or-nsuinteger-in-objective-c) – Caleb Jul 16 '12 at 21:59
  • @Adam Yes, it would seem that 300 should be written as `{0,0,1,44}`, correct? Unless I'm missing something. Then again, the question seems to specify using some odd byte order, so maybe `{44,1,0,0}` or `{0,0,44,1}`? – Alexis King Jul 16 '12 at 22:01
  • @AdamRosenfield I'm sure the OP means that the byte is 0x01, but it represents 256 due to its position. (256*1)+44=300. – Caleb Jul 16 '12 at 22:01
  • @Adam Yes, sorry for that, it was the end of a very long day and I was really frustrated with this (well, as it turns out, with my own shortcomings). Indeed, the correct representation in the latter case was {0,0,1,44}. Thanks to everyone else for pointing this out and not slapping me for a very rookie mistake :) – lucianf Jul 17 '12 at 10:29

3 Answers3

6

The server is asking for the data in big-endian order (most significant byte first). Big-endian is the standard network byte order for Internet protocols (including IP, TCP, UDP, DNS, and lots more). It happens that you're compiling for a little-endian platform, so you need to swap the bytes.

However, you should not rely on being on a little-endian platform. Instead, you should make your code independent of the local (host) byte order, using the Core Foundation byte-swapping functions.

Specifically, you should use CFSwapInt32HostToBig to convert your 4-byte int to big-endian order. On a little-endian platform, this rearranges the bytes. On a big-endian platform, this does nothing.

Similarly, you should use CFSwapInt32BigToHost to convert the 4-byte ints you receive from the server to your host byte order.

Alternatively, you can use the standard POSIX byte-swapping functions. The htonl function stands for host-to-network-long, and converts a 32-bit int from host order to network (big-endian) order. The ntohl function converts a 32-bit int from network to host order. (Back when these functions were created, some popular operating systems had 16-bit ints and 32-bit longs. Can you believe it?)

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Thanks Rob. I was just about to write last night that, even though I saw [this](http://stackoverflow.com/questions/3830862/how-can-i-reverse-the-byte-order-of-an-nsinteger-or-nsuinteger-in-objective-c) before, I was pretty sure this wasn't a case of endianness just because my crc had 4 bytes (and I hadn't realised Int32 was just that). I guess what I was doing was taking an engineering approach (convert the int to a byte array, swap the bytes, convert the result to nsdata)... and missing the very obvious, for which I now feel quite stupid :) Short story: thanks once again, lesson learnt. – lucianf Jul 17 '12 at 10:56
1
NSInteger a = 300; //13;
char* aa = &a;
Byte b[] = {0,0,0,0};
memcpy(&b[0], &aa[3], 1);
memcpy(&b[1], &aa[2], 1);
memcpy(&b[2], &aa[1], 1);
memcpy(&b[3], &aa[0], 1);
ejps
  • 79
  • 3
0

As indicated in the accepted answer for the duplicate question, Foundation provides functions for byte swapping. In this case, since you're dealing with a long, you probably want NSSwapLong.

Caleb
  • 124,013
  • 19
  • 183
  • 272