C - inet_pton () не производит сетевой порядок байтов - PullRequest
0 голосов
/ 06 декабря 2018

Я запутался с функцией inet_pton().Согласно справочной странице

Эта функция преобразует строку символов src в структуру сетевых адресов в семействе адресов af, а затем копирует структуру сетевых адресовдо дст .Аргумент af должен быть либо AF_INET, либо AF_INET6. dst записывается в порядке сетевых байтов.

Таким образом, функция создает значение порядка сетевых байтов.Но я получил этот код:

 struct sockaddr_in a;
 char sip[20];
 inet_pton(AF_INET, "192.168.0.182", (void *)&a.sin_addr);
 inet_ntop(AF_INET, (void *)&a.sin_addr, sip, 20);

 printf("htonl:%08x\n", htonl(a.sin_addr.s_addr));
 printf("inet_pton:%08x\n", a.sin_addr.s_addr);
 printf("inet_ntop:%s\n", sip);

вывод:

htonl:c0a800b6
inet_pton:b600a8c0
inet_ntop:192.168.0.182

вывод inet_pton равен b6.00.a8.c0, который преобразуется в 182.0.168.192, и он также отличается отвыход htonl.

Поскольку htonl преобразует порядок байтов хоста в порядок сетевых байтов, поэтому, если inet_pton производит порядок байтов в сети, я полагаю, что их выходные данные должны быть одинаковыми?Означает ли это, что inet_pton фактически выдает порядок байтов хоста?

, если inet_pton уже выдает network byte order, зачем мне нужно htonl, чтобы получить правильное значение?

1 Ответ

0 голосов
/ 06 декабря 2018

Да, inet_pton помещает байты адреса в буфер назначения в сетевом порядке.Давайте рассмотрим пример, чтобы увидеть, что происходит.Используя ваш адрес «192.168.0.182», inet_pton создает следующие четыре байта:

c0   a8  00  b6    (hex)
192  168 0   182   (dec)

То есть - это сетевой порядок байтов.Когда вы тогда вызываете htonl (что на самом деле не правильно - вы должны вызывать ntohl для преобразования из сетевого порядка в порядок хостов, но, как указал @ZanLynx, эти две функции идентичны на x86), вы переупорядочиваете байты следующим образом:

b6 00 a8 c0

Но затем вы передаете эту форму printf с %x в качестве формата.Это говорит printf интерпретировать четыре байта как одно 32-разрядное целое число, но x86 - это машина с прямым порядком байтов, поэтому, когда он загружает четыре байта как целое число, b6 является байтом самого низкого порядка, а c0 является самым высоким значением, которое дает то, что вы видели:

htonl:c0a800b6

Итак, в общем, если у вас есть IPv4-адрес в сетевой форме, и вы хотите быстро отобразить его (для отладки или чего-либо еще) вПорядок, который «имеет смысл» для вас (программиста), вы бы использовали:

printf("%x\n", ntohl(a.sin_addr.s_addr));

Вы также можете отображать отдельные байты, поскольку они находятся в сетевом порядке (что на самом деле то же самое, но может бытьлегче обернуть голову), просто используйте unsigned char * (или эквивалентно uint8_t * из <stdint.h>), чтобы напечатать отдельные байты:

uint8_t *ipp = (void *)&a.sin_addr.s_addr;
printf("%02x %02x %02x %02x\n", ipp[0], ipp[1], ipp[2], ipp[3]);

(Вы должны использовать тип без знака здесь, чтобыизбегайте расширения знака. В приведенном выше утверждении каждый символ будет повышен до int при вызове printf. Если у вас есть подписанный char, содержащий, скажем, 0xc0, он обычно будет sign-расширенный into 32-битный int: 0xffffffc0.В качестве альтернативы вы можете использовать спецификацию формата "%02hhx", которая явно говорит printf, что вы действительно передаете его char;тогда он будет смотреть только на младший байт каждого повышенного int.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...