Разбор байтов, отправленных через netcat

Я запускаю сервер, использующий сокеты на C++. Как только я подключился к клиенту (используя для этого netcat), у меня есть функция, которая читает то, что отправил клиент, и пытается его проанализировать.

Структура:

struct m
{
           uint8_t m1;
}

struct str
{
           uint64_t a;    
           uint32_t b;
           uint32_t c;
}

Функция:

 int f(int x){
 char s[1024];
 if (read(x,s,sizeof(s)-1) > 0){
      m *msg = reinterpret_cast<m *>(s);
      if (msg->m1 == 0)
          {
           str *st = reinterpret_cast<str *>(s+1);
           uint64_t a = htonll(st->u);     
           uint32_t b = htonl(st->v);
           uint32_t c = htonl(st->w);
           std::cout<<a<<" "<<b<<" "<<c<<std::endl;
          }
  else
  {....
  }
}

Редактировать:

uint64_t htonll(uint64_t value)
{
// The answer is 42
static const int num = 42;

// Check the endianness
if (*reinterpret_cast<const char*>(&num) == num)
{
    const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
    const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));

    return (static_cast<uint64_t>(low_part) << 32) | high_part;
} else
{
    return value;
}
}

В этом конкретном случае проблем с заполнением быть не должно. Я могу правильно разобрать и добраться до *msghead == '0', если условие. Однако я не получаю тех значений, которые ожидаю от a, b and c. Я пробовал много случаев, но значения не имеют особого смысла.

Как я тестирую:

echo -n -e '\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01' | nc localhost 9000

В идеале я должен получить результат как 1 1 1, но я получаю 0 0 0. Кроме того, если я изменю это на

echo -n -e '\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01' | nc localhost 9000

Я получаю 1 0 0

Я не уверен, что что-то не так с порядком байтов, которое я могу исправить, но в любом случае, похоже, есть и другая проблема.

Равно ли порядок байтов на обеих сторонах соединения?

Some programmer dude 28.07.2018 23:13

Также обратите внимание, что 0 не равен '0' с использованием какой-либо кодировки, существующей в настоящее время.

Some programmer dude 28.07.2018 23:14

И наконец, что, по вашему мнению, означает s в htons? Ответ: Это означает короткая, т.е. 16-битное целое число. Стандартной функции преобразования для 64-битных типов нет, но есть для 32-битных целых чисел.

Some programmer dude 28.07.2018 23:15

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

rsaw27 28.07.2018 23:16

Тогда вы не отправляете то, что вы утверждаете, что отправляете. Какой IMO делает весь вопрос почти таким же бесполезным, как и код (в котором отсутствуют объявления переменных, такие как buf или msghead, и какой тип str?). Пожалуйста, читай о том, как задавать хорошие вопросы, узнайте, как создать Минимальный, полный и проверяемый пример, а также прочтите этот контрольный список вопросов.

Some programmer dude 28.07.2018 23:18

И конечно, пожалуйста, узнать, как отлаживать свои программы.

Some programmer dude 28.07.2018 23:20

Извините, я внес некоторые правки, чтобы сделать его более понятным. Теперь я также использую ntohl для 32-битных целых чисел. Я также понял, что шаблон представляет собой ошибку между двумя байтами. В идеале b должен читать \ x00 \ x00 \ x00 \ x01, но он печатает 256 (что было бы заменой двух соседних пар местами). Аналогично для c \ x00 \ x00 \ x01 \ x00 дает мне 1.

rsaw27 28.07.2018 23:25

Проблема, похоже, в том, что только половина битов подбирается в a, b и c посредством переинтерпретации приведения. Я не уверен, почему это так.

rsaw27 28.07.2018 23:27

Помимо неправильного использования функции htons (если вы ее не перегрузили?), Не могли бы вы проверить sizeof(str)? Это то, что вы ожидаете? Между участниками нет прокладки?

Some programmer dude 28.07.2018 23:32

Да. Ровно 16, как и ожидалось. Программа просто выбирает половину байтов, необходимых для b и c.

rsaw27 28.07.2018 23:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
10
525
1

Ответы 1

Вот в чем проблема:

uint64_t a = htons(st->u);     
uint32_t b = htons(st->v);
uint32_t c = htons(st->w);

Если вы прочитаете этот справочник POSIX, вы увидите, что htons предназначен для целых чисел 16 бит, а htonl - для 32-битных целых чисел. Для 64-битных типов функций стандарт не существует.

Однако в Linux, использующем библиотеку GNU C, есть набор функций bswap_x, которые имеют 64-битный вариант.

Я сделал для этого модификации. Я использую функцию, которую нашел в самом stackoverflow для 64-битного варианта, а также htonl для 32-битных int. Я все еще сталкиваюсь с проблемами. Учитываются только последние два байта, и они тоже меняются местами (ввод, о котором я упоминал выше, отправляется netcat).

rsaw27 28.07.2018 23:47

\ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x01 дает мне 256 для a, и если я внесу какие-либо изменения в первые 6 байтов, например \ x00 \ x00 \ x11 \ x00 \ x00 \ x00 \ x01, он по-прежнему остается прежним.

rsaw27 28.07.2018 23:49

@ rsaw27 Ну ваша функция htonllработает. Так может быть проблема в том, что вы не все данные получаете? Вы только проверяете, что read возвращает значение больше, чем 0, но на самом деле не знать, сколько он читает. С TCP вам может потребоваться несколько вызовов для получения всех данных. И пробовали распечатать необработанные данные, которые вы действительно получаете? Вы этого ожидаете?

Some programmer dude 29.07.2018 00:09

Другие вопросы по теме