Порядок байтов с большим массивом символов в C - PullRequest
8 голосов
/ 08 февраля 2009

Эй, ребята, вопрос от новичка C / Networking ...

Я занимаюсь программированием сокетов на C и пытаюсь решить проблемы с порядком байтов. Мой запрос (отправить) в порядке, но когда я получаю данные, все мои байты не в порядке. Я начинаю с чего-то вроде этого ...

char * aResponse= (char *)malloc(512);
int total = recv(sock, aResponse, 511, 0);

При работе с этим ответом каждое 16-битное слово, похоже, имеет обратные байты (я использую UDP). Я пытался исправить это, делая что-то вроде этого ...

    unsigned short * _netOrder= (unsigned short *)aResponse;
    unsigned short * newhostOrder= (unsigned short *)malloc(total);
    for (i = 0; i < total; ++i)
    {
         newhostOrder[i] = ntohs(_netOrder[i]);
    }

Это работает нормально, когда я воспринимаю данные как короткие, однако, если я снова приведу указатель на символ, байты меняются местами. Что я делаю не так?

Спасибо!

Ответы [ 6 ]

10 голосов
/ 08 февраля 2009

Хорошо, кажется, есть проблемы с тем, что вы делаете на двух разных уровнях. Здесь, кажется, частично возникает путаница из-за использования вами указателей, типа объектов, на которые они указывают, а затем интерпретации кодирования значений в памяти, на которые указывают указатель (и).

Кодирование многобайтовых объектов в памяти - это то, что называется порядком байтов. Две общие кодировки называются Little Endian (LE) и Big Endian (BE). В LE 16-разрядная величина, такая как короткое замыкание, сначала кодируется младшим значащим байтом (LSB). Под BE самый старший байт (MSB) кодируется первым.

По соглашению сетевые протоколы обычно кодируют вещи в то, что мы называем «сетевым порядком байтов» (NBO), которое также совпадает с BE. Если вы отправляете и получаете буферы памяти на платформах с прямым порядком байтов, вы не столкнетесь с проблемами преобразования. Однако ваш код будет зависеть от платформы в соответствии с соглашением BE. Если вы хотите написать переносимый код, который работает корректно как на платформах LE, так и на платформе BE, вы не должны предполагать, что платформа является инициатором.

Достижение переносимости в порядке байтов является целью таких процедур, как ntohs () , ntohl () , htons () и htonl () . Эти функции / макросы определены на данной платформе для выполнения необходимых преобразований на отправляющей и принимающей сторонах:

  • htons () - преобразовать короткое значение из заказа хоста в сетевой заказ (для отправки)
  • htonl () - преобразовать длинное значение из заказа хоста в сетевой заказ (для отправки)
  • ntohs () - преобразовать короткое значение из сетевого заказа в заказ хоста (после получения)
  • ntohl () - преобразовать длинное значение из сетевого заказа в заказ хоста (после получения)

Поймите, что ваш комментарий о доступе к памяти при приведении к символам не влияет на фактический порядок объектов в памяти. То есть, если вы обращаетесь к буферу в виде последовательности байтов, вы увидите байты в том порядке, в котором они фактически были закодированы в памяти, независимо от того, есть ли у вас машина BE или LE. Так что, если вы смотрите на буфер, закодированный NBO после получения, MSB будет первым - всегда. Если вы посмотрите на выходной буфер после того, как вы преобразовали обратно в порядок хостов, если у вас есть машина BE, порядок байтов не изменится. И наоборот, на компьютере LE все байты теперь будут инвертированы в преобразованном буфере.

Наконец, в цикле преобразования переменная total ссылается на байты. Однако вы обращаетесь к буферу как shorts. Ваша защита от петель не должна быть total, но должна быть:

total / sizeof( unsigned short )

для учета двухбайтовой природы каждого short.

3 голосов
/ 08 февраля 2009

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

Это то, что я ожидал.

Что я делаю не так?

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

Google для учебных пособий, связанных с API ntohs, htons и htons.

2 голосов
/ 08 февраля 2009

Непонятно, что представляет aResponse (строка символов? Struct?). Порядковый номер относится только к числовым значениям, а не char с. Вам также необходимо убедиться, что на стороне отправителя все числовые значения преобразуются из хоста в сетевой порядок байтов (hton*).

1 голос
/ 08 февраля 2009

Помимо вашего исходного вопроса (на который, я думаю, уже был дан ответ), вам следует взглянуть на ваше заявление malloc . malloc выделяет байты, а неподписанный шорт, скорее всего, будет два байта.

Ваше заявление должно выглядеть так:

unsigned short *ptr = (unsigned short*) malloc(total * sizeof(unsigned short));
0 голосов
/ 30 июня 2011

Для одного байта нас может не волновать порядок байтов.

0 голосов
/ 08 февраля 2009

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

...