3

I'm making an iOS socket client for my iPhone. I need to send some bytes through tcp/ip. The general idea is, that I want to store multiple values in a single byte array, to avoid several writes to the stream. Take this example:

uint8_t buffer[1024]; // buffer to hold all data I'm sending

NSString *command = @"Broadcast"; // the actual message i want to send
int length = [command length]; // length of said message

Now, for the first 4 positions in the buffer array, i want to put the length variable, and from 4-13, i want to put the actual message. I know how to decode it on the server end, but I can't quite figure out how to get this data into the buffer array, so I have one array with all the data I want to send.

Any help much appreciated!

3 Answers 3

2

Consider the following code:

// First, we get the C-string (NULL-terminated array of bytes) out of NSString.
const char *cString = [command UTF8String];

// The length of C-string (a number of bytes!) differs terribly from
// NSString length (number of characters! Unicode characters are 
// of variable length!).
// So we get actual number of bytes and clamp it to the buffer
// size (so if the command string occasionally gets larger than our
// buffer, it gets truncated).
size_t byteCount = MIN(BUFFER_SIZE - 4,
                       [command lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);

// Now we're using C type conversion to reinterpret the buffer as a
// pointer to int32_t. The buffer points to some memory, it's up to us
// how to treat it.
*(int32_t *)buffer = byteCount;

// And finally we're copying our string bytes to the rest of the buffer.
memcpy(buffer + 4, cString, byteCount); 

There's a caveat in this code - it uses host byte order to store uint32_t variable, so if you're passing this buffer over network, it's generally a good idea to make your byte order fixed (networking historically employs big-endianness, though most of the computers are nowadays little-endian).

To fix the byte order just replace the line

*(int32_t *)buffer = byteCount;

with

*(int32_t *)buffer = htonl(byteCount);

And don't forget to convert byte ordering back when processing this buffer on other computer!

Sign up to request clarification or add additional context in comments.

2 Comments

It appears that your answer is working for me, however I'm having a hard time understanding what it actually does. Would you mind terribly expanding the example, say I wanted to append the length of a message to the end of the buffer, and append the message after that, how would I go about doing this?
@cnh1991 And if you wanted to write length at the very end of the buffer, the following code will go: *(uint32_t *)(buffer + 1020) = byteCount. It reinterprets buffer + 1020, e.g. 1020 chars from the buffer beginning, as the pointer to uint32_t.
0

You can send it as C string:

const char * cString = [command UTF8String];
length = strlen(cString);

for (int i = 0; i < length; ++i) {
    buffer[i + 4] = cString[i];
}

buffer[0] = length & 0xff;
buffer[1] = (length >> 8)  & 0xff;
buffer[2] = (length >> 16) & 0xff;
buffer[3] = (length >> 24) & 0xff;

3 Comments

This adds the command string to the buffer like i need yes. But how do i put a byte representation of the string length, in the first 4 elements of the buffer?
This code will break if using non-ASCII characters - [NSString length] returns number of characters, not the number of bytes.
@iHunter ok, took that into account.
0

This is NOT production code, it overflows if size large and lacks error checks. Should give you an idea of what needs to be done.

const int SIZE = 64;
const int SIZE_OFFSET = 0;
const int MESSAGE_OFFSET = 4;


// Set up the buffer.
Byte buffer[SIZE];
for (int i = 0; i < SIZE; i++) {
    buffer[i] = 0;
}
uint8 *ptr; // Used to traverse data.

NSString *command= @"Broadcast";

// note: non ASCII characters, such as é,  will consume 2 bytes.
NSData *data = [command dataUsingEncoding:NSUTF8StringEncoding];
// uint32 ensures we get a 4 byte integer on non 32bit systems.
uint32 dataLength = [data length] ; // Number of bytes stored in data.

// Place dataLength into the first 4 elements of the buffer. Keep endianness in mind.
*ptr = &dataLength;
for (int8_t iterator = SIZE_OFFSET; iterator < sizeof(uint32) + SIZE_OFFSET; iterator++) {
    buffer[iterator] = ptr[iterator];
}

// todo, place data into buffer.

1 Comment

Why aren't you using memset for zeroing out the buffer and memcpy for copying string to buffer?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.