2. Если служба предоставляется для множества типов сокетов, то одна структура может быть возвращена для каждого типа сокета в зависимости от
ai_socktype
. (Заметьте, что большинство реализаций
getaddrinfo
считают, что номер порта используется только тем типом сокета, который запрашивается в
ai_socktype
. Если аргумент
ai_socktype
не определен, функция возвращает ошибку.)
Например, если структура
hints
пуста, а вы запрашиваете записи для службы
domain
на узле с двумя IP-адресами, возвращаются четыре структуры
addrinfo
:
■ одна для первого IP-адреса и типа сокета SOCK_STREAM;
■ одна для первого IP-адреса и типа сокета SOCK_DGRAM;
■ одна для второго IP-адреса и типа сокета SOCK_STREAM;
■ одна для второго IP-адреса и типа сокета SOCK_DGRAM.
Мы показываем схематическое изображение этого примера на рис. 11.3. Не существует никакого гарантированного порядка структур при возвращении множества элементов. Например, мы не можем считать, что службы TCP возвращаются перед службами UDP.
Рис. 11.3. Пример информации, возвращаемой функцией getaddrinfo
ПРИМЕЧАНИЕ
Хотя это и не гарантируется, реализация должна возвращать IP-адреса в том же порядке, в котором они возвращаются DNS. Некоторые распознаватели позволяют администратору указывать порядок сортировки адресов в файле /etc/resolv.conf. Протокол IPv6 определяет правила выбора адресов (RFC 3484 [28]), которые могут влиять на порядок адресов, возвращаемых getaddrinfo.
Информация, возвращаемая в структурах
addrinfo
, готова для передачи функциям
socket
и
connect
или
sendto
(для клиента) и
bind
(для сервера). Аргументы функции
socket
— это элементы
ai_family
,
ai_socktype
и
ai_protocol
. Второй и третий аргументы функций
connect
и
bind
— это элементы
ai_addr
(указатель на структуру адреса сокета соответствующего типа, заполняемую функцией
getaddrinfo
) и
ai_addrlen
(длина этой структуры адреса сокета).
Если в структуре
hints
установлен флаг
AI_CANONNAME
, элемент
ai_canonname
первой возвращаемой структуры указывает на каноническое имя узла. В терминах DNS это обычно полное доменное имя (FQDN). Программы типа
telnet
широко используют этот флаг для того, чтобы выводить канонические имена систем, к которым производится подключение. Пользователь может указать короткое имя узла или его альтернативное имя, но он должен знать, с какой системой он в результате соединился.
На рис. 11.3 представлена возвращаемая информация для следующего вызова:
struct addrinfo hints, *res;
bzero(&hints, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET;
getaddrinfo("bsdi", "domain", &hints, &res);
На этом рисунке все, кроме переменной
res
, относится к динамически выделяемой памяти (например, с помощью функции
malloc
). Предполагается, что каноническое имя узла
freebsd4
—
freebsd4.unpbook.com
, и что этот узел имеет два адреса IPv4 в DNS.
Порт 53 предназначен для службы
domain
, и нужно учитывать, что этот номер порта будет представлен в структурах адресов сокетов в сетевом порядке байтов. Мы приводим возвращаемые значения
ai_protocol
IPPROTO_TCP и IPPROTO_UDP. Функция
getaddrinfo
может возвращать значение
ai_protocol
равное 0 для структур SOCK_STREAM, если этого достаточно для однозначного определения протокола (типа сокета недостаточно, например, если в системе помимо TCP реализован и SCTP), и 0 для структур SOCK_DGRAM, если в системе не реализованы другие протоколы дейтаграмм для IP (на момент написания этой книги стандартизованных протоколов еще не было, но два уже разрабатывались IETF). Лучше всего, если
getaddrinfo
всегда будет возвращать конкретный тип протокола.
В табл. 11.1 показано число структур
addrinfo
для каждого возвращаемого адреса, определяемое на основе заданного имени службы (которое может быть представлено десятичным номером порта) и рекомендации
ai_socktype
.
Таблица 11.1. Число структур addrinfo, возвращаемых для каждого IP-адреса
Элемент ai_socktype | Служба обозначена именем и предоставляется: | Служба обозначена именем порта |
Только TCP | Только UDP | Только SCTP | TCP и UDP | TCP и SCTP | TCP, UDP и SCTP |
0 | 1 | 1 | 1 | 2 | 2 | 3 | Ошибка |
SOCK_STREAM | 1 | Ошибка | 1 | 1 | 2 | 2 | 2 |
SOCK_DGRAM | Ошибка | 1 | | 1 | Ошибка | 1 | 1 |
SOCK_SEQPACKET | Ошибка | Ошибка | 1 | Ошибка | 1 | 1 | 1 |
Более одной структуры
addrinfo
возвращается для каждого IP-адреса только в том случае, когда поле
ai_socktype
структуры
hints
пусто и либо служба поддерживается TCP и UDP (как указано в файле
/etc/services
), либо задан номер порта для этой службы.