Предположим, у нас есть struct sockaddr_in ina и IP-адрес "10.12.110.57" или 2001:db8:63b3:1::3490, который вы хотите сохранить в этой структуре.
Для этого нужна функция inet_pton(), она конвертирует строку адреса в структуру struct in_addr или struct in_6addr, в зависимости от указания семейства адресов AF_INET (для IPv4) ли AF_INET6 (для IPv6).
pton - означает "Presentation to network", можно просто сказать - строка к сетевой структуре.
Пример конвертации для IPv4 и для IPv6:
struct sockaddr_in sa; //IPv4 struct sockaddr_in6 sa6; //IPv6 // inet_pton() возвращает -1 в случае ошибке, нужно это обрабатывать! inet_pton(AF_INET, "10.12.110.57", &(sa.sin_addr)); inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr));
Старый способ включен в себя вызов функции
inet_addr()илиinet_aton(), сейчас это устаревший способ, который не работает с IPv6.
Функция inet_ntop() используется для преобразования бинарного адреса (уже полученного откуда-то) в строку.
ntop означает Network to represetntation
Пример вывода адреса для IPv4 и IPv6:
// IPv4: char ip4[INET_ADDRSTRLEN]; // буфер для хранения IPv4 строки struct sockaddr_in sa; // предположим, что уже загружен откуда-то inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN); printf("IPv4 Address: %s\n", ip4); // IPv6: char ip6[INET6_ADDRSTRLEN]; struct sockaddr_in6 sa6; inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN); printf("IPv6 Address: %s\n", ip6);
Эти функции работают только с прямым, числовым адресом (xxx.xxx.xxx.xxx или IPv6), они не делают поиска в DNS-сервере по имени хоста (например, example.com). Для этих целей есть другая функция - getaddrinfo(), с которой ознакомимся позже.
Чтобы ваш код поддерживал обе версии - IPv4 и IPv6, можно следовать следующим наставлениям:
-
Используйте системную функцию
getaddrinfo(), чтобы получать все структурыstruct sockaddr. Это сделает ваш код независимым от версии IP. -
Любое место, где происходит жесткое кодирование конкретной версии IP, оберните в функцию-помощник, которая сама подставляет нужные значения (IPv4 или IPv6).
-
Если вам нужен IPv6, то:
-
заменяйте константу
AF_INETнаAF_INET6. -
заменяйте константу
PF_INETнаPF_INET6. -
изменяйте назначение
IN_ADDRANYкin6addr_any:struct sockaddr_in sa; struct sockaddr_in6 sa6; sa.sin_addr.s_addr = INADDR_ANY; // использовать IPv4 sa6.sin6_addr = in6addr_any; // использовать IPv6
-
используйте значение
IN6ADDR_ANY_INITдля инициализацииstruct in6_addr:struct in6_addr ia6 = IN6ADDR_ANY_INIT.
-
вместо
struct sockaddr_in, используйтеstruct sockaddr_in6, удостоверьтесь, что вы работаете с полями, где есть указание "6", что они конкретно для IPv6. -
вместо
struct in_addr, используйтеstruct in6_addr, удостоверьтесь, что вы работаете с полями, где есть указание "6", что они конкретно для IPv6.
-
-
вместо
inet_aton()илиinet_addr(), используйтеinet_pton(). -
вместо
inet_ntoa(), используйтеinet_ntop(). -
вместо
gethostbyname(), используйтеgetaddrinfo(). -
вместо
gethostbyaddr(), используйтеgetnameinfo().