Наиболее распространенной причиной, по которой одному имени хоста ставится в соответствие несколько IP-адресов, является балансировка нагрузки. Серверы имен (программы, предлагающие преобразование имен хостов в IP-адреса) часто конфигурируются так, что возвращают в разное время разные адреса для одного и того же имени. Это позволяет нескольким физическим машинам поддерживать единую службу.
Появление IPv6 повлекло за собой еще одну причину, по которой одно имя хоста должно иметь несколько адресов. Многие машины сейчас имеют одновременно и IPv4-, и IPv6-адреса.
Библиотечная функция
getaddrinfo
[134] предлагает программам простой доступ к преобразованиям имен хостов DNS.
#include <sys/types.h>
#include <socket.h>
#include <netdb.h>
int getaddrinfo(const char * hostname, const char * servicename,
этой функции достаточно простая, однако весьма мощная, в связи с этим ее описание может показаться несколько запутанным. Идея заключается в том, что функция принимает имя хоста, имя службы (или оба из них) и превращает их в список IP-адресов. Затем с использованием
hints
список фильтруется и те адреса, которые не нужны приложению, отбрасываются. Окончательный список возвращается в виде связного списка в переменной
res
.
134
Если у вас большой опыт в программировании сокетов (или вы сравниваете данную книгу с ее первым изданием), то вы обязательно заметите, что функции, применявшиеся для преобразования имен, значительно изменились. Эти изменения позволяют создавать программы абсолютно независимо от того протокола, который они используют. Теперь гораздо легче разрабатывать программы, работающие как на IPv4-, так и на IPv6-машинах. Они также должны распространяться на остальные протоколы, хотя функция
getaddrinfo
в данный момент работает только для IPv4 и IPv6.
Искомое имя хоста содержится в первом параметре и может равняться
NULL
, если производится поиск только службы. Параметр
hostname
может быть именем (например,
www.ladweb.net
) или IP-адресом (с точками или двоеточиями в качестве разделителей), который функция
getaddrinfo
преобразует в двоичный адрес.
Второй параметр
servicename
указывает имя той службы, для которой нужно извлечь официальный порт. Если он равен
NULL
, то поиск службы не выполняется.
Структура
struct addrinfo
используется как для
hints
(при фильтрации полного списка адресов), так и для передачи окончательного списка в приложение.
#include <netdb.h>
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr_t * ai_addr;
char * ai_canonname;
struct addrinfo * next;
}
Если
struct addrinfo
используется для параметра
hints
, то участвуют только первые четыре члена, остальные должны равняться нулю или
NULL
. Если задано значение
ai_family
, то
getaddrinfo
возвращает адреса только для указанного семейства протоколов (например,
PF_INET
). Аналогично, если устанавливается
ai_socktype
, то возвращаются только адреса данного типа сокета.
Член
ai_protocol
позволяет ограничивать результаты определенным протоколом. Этот параметр нельзя применять, если не установлен параметр
ai_family
, а также, если числовое значение протокола (такое как
IPPROTO_TCP
) не является уникальным среди всех протоколов; он хорошо подходит только для
PF_INET
и
PF_INET6
.
Последний член, используемый для
hints
—
это
aflags
, который принимает одно или несколько (объединенных логическим "ИЛИ") из перечисленных ниже значений.
AI_ADDRCONFIG
По умолчанию функция
getaddrinfo
возвращает все адреса, соответствующие запросу. Данный флаг указывает на возврат адресов только тех протоколов, чьи адреса сконфигурированы в локальной системе. Другими словами, она возвращает только IPv4-адреса в системах с IPv4-интерфейсами и только IPv6-адреса в системах с интерфейсами IPv6.
AI_CANONNAME
При возврате поле
ai_canonname
содержит каноническое имя хоста для адреса, указанного в
struct addrinfo
. Поиск этого адреса сопровождается дополнительными поисками в службе DNS и, как правило, не является необходимым.
AI_NUMERICHOST
Параметр
hostname
должен представлять собой адрес в форме с разделительными запятыми или двоеточиями. Никакие преобразования имени хоста не выполняются. Это предохраняет
getaddrinfo
от каких-либо поисков имени хоста, которые могут оказаться весьма длительным процессом.
AI_PASSIVE
Если hostname равен
NULL
и присутствует этот флаг, то возвращается неустановленный адрес, который позволяет ожидать соединений на всех интерфейсах. Если данный флаг не указан (а значение
Адрес обратной связи — это специальный адрес, который позволяет программам взаимодействовать через TCP/IP с приложениями только на одной и той же машине.
Последний параметр
res
в
getaddrinfo
должен быть адресом указателя на
struct addrinfo
. Для успешного завершения переменная, на которую указывает
res
, устанавливается на первую запись в односвязном списке адресов, который соответствует запросу. Член
ai_next
структуры
struct addrinfo
указывает на следующий член связного списка, и для последнего узла в списке параметр
ai_next
равен
NULL
.
Когда приложение завершает работу с возвращенным связным списком, функция
freeaddrinfo
освобождает память, занимаемую списком.
#include <sys/types.h>
#include <socket.h>
#include <netdb.h>
void freeaddrinfo(struct addrinfo * res);
Единственным параметром для
freeaddrinfo
является указатель на первый узел в списке.
Каждый узел в возвращаемом списке имеет тип
struct addrinfo
и специфицирует один адрес, соответствующий запросу. Каждый адрес содержит не только IPv4- или IPv6-адрес, он также определяет тип соединения (например, дейтаграмма) и протокол (такой как UDP). Если для одного IP-адреса в запросе подходит несколько типов соединений, то данный адрес включается в несколько узлов.
Каждый узел содержит описанную ниже информацию.
•
ai_family
— семейство протоколов (
PF_INET
или
PF_INET6
), к которому принадлежит адрес.
•
ai_socktype
— тип соединения для адреса (как правило, принимает одно из значений