2014-06-08 2 views
0

Хороший день для всех.Java ByteBuffer -> [NSData bytes] до UInt16

Я пишу клиент-серверное приложение на основе сокетов. Сервер написан с Java, клиент - с Objective-C на IOS SDK 7.

Мой сервер записывает данные на подключенный сокет со следующим кодом:

//Socket client = new ...; 
DataOutputStream out = new DataOutputStream(client.getOutputStream()); 
// send package 
String message = "pings"; // package body 
byte bodySize = (byte) message.length(); 
java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(2 + 2 + 1 + bodySize); 
buffer.putShort((short) 16); // package ID (2 bytes) 
buffer.putShort((short) 7); // package header (2 bytes, bitmask options) 
buffer.put(bodySize); // calculate & put body size in 5th byte (1 byte) 
buffer.put(message.getBytes()); // put the message to buffer (+5 bytes) 

out.write(buffer.array()); // write to stream 
out.close(); // close stream 

Тогда я пытаюсь разобрать принятый NSData в клиенте Objective-C. Вот код:

- (UInt16)packageIdFromPackageHead:(NSData *)data { 
    const void *bytes = [data bytes]; 
    UInt16 packageId; 
    memcpy(&packageId, bytes + 0, 2); // get first 2 bytes, it must be short = 16 
    return packageId; 
} 

Но в переменной «packageId» значение «4096». Что это? Где мое 16-значное десятичное значение?

Далее, я пытаюсь получить следующее значение, «заголовок пакета». Я написал следующий код:

UInt16 header; 
memcpy(&header, bytes + 2, 2); // skip first 2 bytes, copy next 2 bytes, must be short = 7 

Я получил огромное значение, 1792. Почему? Что означает это число? Я попробовал несколько смещений, +2, +3 - ничего. Я не могу получить правильное значение. Я пытался использовать некоторые преобразования в

header = CFSwapInt32BigToHost(header); 

или

header = CFSwapInt32HostToBig(header); 

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

Далее, когда я попытался получить 5-й байт (он содержит нашу длину строки сообщения, вы помните). Вот код:

UInt8 bodySize; 
memcpy(&bodySize, bytes + 4, 1); // get the 5th byte 

я получил значение

'\x05' 

И это правильно.

Я почти уверен, что значение входного NSData * верное. Здесь вы можете увидеть скриншот дампа памяти из Xcode:

Debug mode. Input NSData * memory dump

Где проблема? В коде сервера? Или в моем клиенте чтение кода? Пожалуйста, помогите, я потратил 2 дня, чтобы найти решение, и я все равно не смог его получить.

+0

'memcpy (& packageId, bytes + 0, 2);' - где вы получаете 'bytes' из? –

+0

И если вы NSLog объект NSData, вы получите шестнадцатеричный дамп, который вы можете проверить, чтобы определить, что вы получили. –

+0

Да, моя ошибка. Bytes - 'const void * bytes = [data bytes]'. Я исправил описание моего вопроса. Благодарю. – George

ответ

0

Благодаря горячим ликам!

Правильный код клиента:

const void *bytes = [data bytes]; 
UInt16 packageId; // 16-bit value 
memcpy(&packageId, bytes + 0, 2); // copy first 2 bytes 
packageId = CFSwapInt16BigToHost(packageId); // fix endianness for 16-bit value 
return packageId; // now we got correct value 

Или, и это более удобно, изменять Java-код на сервере с:

java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(2 + 2 + 1 + bodySize); 
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN); 

После этой модификации исходного кода клиент будет корректно работать без использования Функции CFSwapInt ....

Много-много спасибо за помощь!