Функция getaddrinfo() является современным аналогом устаревших функций gethostbyname() и getservbyname(). Если передать ей имена узла и службы, то она вернет набор структур, содержащих соответствующие IP-адреса (их может быть несколько) и номер порта в двоичном виде. В отличие от gethostbyname(), функция getaddrinfo() умеет прозрачно работать с адресами в форматах IPv4 и IPv6, поэтому ее можно использовать для написания программ, которые не зависят от версии протокола IP. Данную функцию следует применять во всех новых программах для преобразования имен узлов и служб в двоичное представление.
Функция getnameinfo() выполняет обратное преобразование, превращая IP-адрес и номер порта в соответствующие имена узла и службы.
С помощью функций getaddrinfo() и getnameinfo() можно также переводить IP-адрес в презентационный формат и обратно.
Прежде чем приступать к подробному обсуждению этих функций в разделе 55.10, сначала необходимо рассмотреть службу DNS (см. раздел 55.8) и файл /etc/services (см. раздел 55.9). DNS позволяет совместно работающим серверам обслуживать распределенные базы данных, которые привязывают IP-адреса к именам узлов и наоборот. Существование таких служб, как DNS, необходимо для работы Интернета, поскольку централизованное управление всеми существующими именами узлов было бы попросту невозможным. Файл /etc/services привязывает номера портов к символьным именам служб.
Функции inet_pton() и inet_ntop() позволяют преобразовывать IPv4- и IPv6-адреса между двоичным и презентационным (десятичные числа, разделенные точками, или шестнадцатеричная строка) форматами. Буква p в именах этих функций обозначает
#include
int inet_pton(int
Возвращает 1 при успешном завершении, 0, если строка src_str не соответствует презентационному формату, или -1 при ошибке
const char *inet_ntop(int
size_t
Возвращает указатель на dst_str или NULL при ошибке
Презентационный вид представляет собой строку, понятную для человека. Например:
• 204.152.189.116 (IPv4-адрес в виде десятичных чисел, разделенных точками);
•::1 (IPv6-адрес в виде шестнадцатеричных значений, разделенных двоеточиями);
•::FFFF:204.152.189.116 (IPv4-адрес, совместимый с IPv6).
Функция inet_pton() переводит презентационную строку, переданную в аргументе src_str, в двоичный IP-адрес с сетевым порядком следования байтов. Аргумент domain должен быть равен AF_INET или AF_INET6. Полученный адрес помещается в структуру, на которую указывает аргумент addrptr; тип структуры должен быть либо in_addr, либо in6_addr, в зависимости от значения domain.
Функция inet_ntop() выполняет обратное преобразование. Повторим: аргумент domain должен быть равен AF_INET или AF_INET6, а указатель addrptr должен ссылаться на структуру типа in_addr или in6_addr, которую мы хотим преобразовать. Итоговая строка с нулевым символом в конце помещается в буфер, на который указывает dst_str. Аргумент len должен содержать размер этого буфера. В случае успеха функция inet_ntop() возвращает dst_str. Если размер len слишком маленький, то inet_ntop() возвращает NULL, а глобальной переменной errno присваивается ENOSPC.
Чтобы подобрать подходящий размер буфера, на который указывает аргумент dst_str, можно использовать две константы, определенные в заголовочном файле
#define INET_ADDRSTRLEN 16 /* Максимальный размер строки с десятичными числами,
разделенными точками (IPv4) */
#define INET6_ADDRSTRLEN 46 /* Максимальный размер шестнадцатеричной строки (IPv6) */
Примеры использования inet_pton() и inet_ntop() приведены в следующем разделе.
В этом разделе мы возьмем клиентскую и серверную программы для изменения регистра, показанные в разделе 53.3, и перепишем их с учетом использования датаграммных сокетов в домене AF_INET6. Исходный код будет представлен с минимальными комментариями, поскольку по своей структуре он похож на ранее рассмотренные программы. Главное отличие новой версии заключается в определении и инициализации структуры с адресом сокета в формате IPv6, которую мы описали в разделе 55.4.
И клиент, и сервер задействуют заголовочный файл, показанный в листинге 55.2. В этом файле определяется номер порта сервера и максимальный размер сообщений, которыми клиент и сервер могут обмениваться между собой.