2013-08-29 2 views
3

Я создаю клиент сокета iOS для своего iPhone. Мне нужно отправить несколько байтов через tcp/ip. Основная идея заключается в том, что я хочу хранить несколько значений в одном байтовом массиве, чтобы избежать нескольких операций записи в поток. Возьмем такой пример:Байт-массив, содержащий целочисленное и строковое представление

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 

Теперь, в течение первых 4-х позиций в массиве буфера, я хочу, чтобы поместить переменную длину, и от 4-13, я хочу поставить реальное сообщение. Я знаю, как его декодировать на сервере, но я не могу понять, как получить эти данные в массив буфера, поэтому у меня есть один массив со всеми данными, которые я хочу отправить.

Любая помощь очень ценится!

ответ

2

Рассмотрим следующий код:

// 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); 

Там один нюанс в этом коде - он использует машинную последовательность байт для хранения uint32_t переменной, так что если вы передаете этот буфер по сети, обычно рекомендуется сделать ваш порядок байтов фиксированным (в сети исторически используется big-endianness, хотя большинство компьютеров в настоящее время малоподобны).

Чтобы зафиксировать порядок байтов просто заменить строку

*(int32_t *)buffer = byteCount; 

с

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

И не забудьте преобразовать порядок байтов обратно при обработке этого буфера на другом компьютере!

+0

Кажется, что ваш ответ работает на меня, однако мне трудно понять, что он на самом деле делает. Не могли бы вы серьезно расширить пример, скажем, я хотел бы добавить длину сообщения в конец буфера и добавить сообщение после этого, как бы я это сделал? –

+0

@ cnh1991 Я добавил комментарии к своему коду. Надеюсь, поможет. – iHunter

+0

@ cnh1991 И если вы хотите записать длину в самом конце буфера, следующий код будет идти: '* (uint32_t *) (buffer + 1020) = byteCount'. Он переинтерпретирует «буфер + 1020», например. 1020 символов из начала 'buffer', как указатель на' uint32_t'. – iHunter

0

Вы можете отправить его в виде строки C:

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; 
+0

Это добавляет строку команд в буфер, как будто мне нужно. Но как я могу поместить байтовое представление длины строки в первые 4 элемента буфера? –

+0

добавить код для ввода длины в первые 4 байта. – Kirsteins

+0

Этот код будет разбит, если использовать символы, отличные от ASCII, - '[NSString length]' возвращает количество символов, а не количество байтов. – iHunter

0

Это не производственный код, он переполняется, если размер большой и отсутствует проверка ошибок. Должен дать вам представление о том, что нужно сделать.

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. 
+0

Почему вы не используете 'memset' для обнуления буфера и' memcpy' для копирования строки в буфер? – iHunter

+0

Я забыл про этих двух! Спасибо за напоминание! –

Смежные вопросы