Я запускаю сервер, использующий сокеты на 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
Я не уверен, что что-то не так с порядком байтов, которое я могу исправить, но в любом случае, похоже, есть и другая проблема.
Также обратите внимание, что 0
не равен '0'
с использованием какой-либо кодировки, существующей в настоящее время.
И наконец, что, по вашему мнению, означает s
в htons
? Ответ: Это означает короткая, т.е. 16-битное целое число. Стандартной функции преобразования для 64-битных типов нет, но есть для 32-битных целых чисел.
Я использую localhost, поэтому порядок байтов равен. Это сравнение работает, основная проблема в том, почему я получаю такие абсурдные результаты для последнего оператора печати.
Тогда вы не отправляете то, что вы утверждаете, что отправляете. Какой IMO делает весь вопрос почти таким же бесполезным, как и код (в котором отсутствуют объявления переменных, такие как buf
или msghead
, и какой тип str
?). Пожалуйста, читай о том, как задавать хорошие вопросы, узнайте, как создать Минимальный, полный и проверяемый пример, а также прочтите этот контрольный список вопросов.
И конечно, пожалуйста, узнать, как отлаживать свои программы.
Извините, я внес некоторые правки, чтобы сделать его более понятным. Теперь я также использую ntohl для 32-битных целых чисел. Я также понял, что шаблон представляет собой ошибку между двумя байтами. В идеале b должен читать \ x00 \ x00 \ x00 \ x01, но он печатает 256 (что было бы заменой двух соседних пар местами). Аналогично для c \ x00 \ x00 \ x01 \ x00 дает мне 1.
Проблема, похоже, в том, что только половина битов подбирается в a, b и c посредством переинтерпретации приведения. Я не уверен, почему это так.
Помимо неправильного использования функции htons
(если вы ее не перегрузили?), Не могли бы вы проверить sizeof(str)
? Это то, что вы ожидаете? Между участниками нет прокладки?
Да. Ровно 16, как и ожидалось. Программа просто выбирает половину байтов, необходимых для b и c.
Вот в чем проблема:
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).
\ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x01 дает мне 256 для a, и если я внесу какие-либо изменения в первые 6 байтов, например \ x00 \ x00 \ x11 \ x00 \ x00 \ x00 \ x01, он по-прежнему остается прежним.
@ rsaw27 Ну ваша функция htonll
работает. Так может быть проблема в том, что вы не все данные получаете? Вы только проверяете, что read
возвращает значение больше, чем 0
, но на самом деле не знать, сколько он читает. С TCP вам может потребоваться несколько вызовов для получения всех данных. И пробовали распечатать необработанные данные, которые вы действительно получаете? Вы этого ожидаете?
Равно ли порядок байтов на обеих сторонах соединения?