UNIX: разработка сетевых приложений
Обратите внимание, что табл. 11.3 описывает только обработку адресов IPv4 и IPv6 функцией
, то есть количество и тип адресов, возвращаемых процессу в различных ситуациях. Реальное количество структурgetaddrinfoзависит также от типа сокета и имени службы, о чем уже говорилось в связи с табл. 11.1.addrinfo11.10. Функция getaddrinfo: примеры
Теперь мы покажем некоторые примеры работы функции
, используя тестовую программу, которая позволяет нам вводить все параметры: имя узла, имя службы, семейство адресов, тип сокета и флагиgetaddrinfoиAI_CANONNAME. (Мы не показываем эту тестовую программу, поскольку она содержит около 350 строк малоинтересного кода. Ее можно получить тем же способом, что и прочие исходные коды для этой книги.) Тестовая программа выдает информацию о переменном числе возвращаемых структурAI_PASSIVE, показывая аргументы вызова функцииaddrinfoи адрес в каждой структуре адреса сокета. Сначала показываем тот же пример, что и на рис. 11.3:socketfreebsd % <b>testga -f inet -c -h freebsd4 -s domain</b>socket(AF_INET, SOCK_DGRAM, 17) ai_canonname = freebsd4.unpbook.comaddress: 135.197.17.100:53socket(AF_INET, SOCK_DGRAM, 17)address: 172:24.37.94:53socket(AF_INET, SOCK_STREAM, 6) ai_canonname = freebsd4.unpbook.comaddress: 135.197.17.100:53socket(AF_INET, SOCK_STREAM, 6)address: 172.24.37.94:53Параметр
задает семейство адресов, -с указывает, что нужно возвратить каноническое имя,-f inetзадает имя узла,-h freebsd4задает имя службы.-s domainТипичный сценарий клиента — задать семейство адресов, тип сокета (параметр
), имя узла и имя службы. Следующий пример показывает это для узла с несколькими сетевыми интерфейсами с шестью адресами Ipv4:-tfreebsd % <b>testga -f inet -t stream -h gateway.tuc.noao.edu -s daytime</b>socket(AF_INET, SOCK_STREAM, 6)address: 140.252.108.1:13socket(AF_INET, SOCK_STREAM, 6)address: 140.252.1.4:13socket(AF_INET, SOCK_STREAM, 6)address: 140.252.104.1:13socket(AF_INET, SOCK_STREAM, 0)address: 140.252.3.6.13socket(AF_INET, SOCK_STREAM, 0)address: 140.252.4.100.13socket(AF_INET, SOCK_STREAM, 0)address: 140.252.1.4.13Затем мы задаем наш узел
, у которого имеется и запись типа AAAA, и запись типа А, не указывая семейства адресов. Имя службы —aix, которая предоставляется только TCP.ftpfreebsd % <b>testga -h aix -s ftp -t stream</b>socket(AF_NET6, SOCK_STREAM, 6)address: [3ffe:b80:1f8d:2:204:acff:fe17:bf38]:21socket(AF_INET, SOCK_STREAM, 6)address: 192.168.42.2:21Поскольку мы не задали семейство адресов и запустили этот пример на узле, который поддерживает и IPv4, и IPv6, возвращаются две структуры: одна для IPv6 и одна для IPv4.
Затем мы задаем флаг
(параметрAI_PASSIVE), не указываем ни семейства адресов, ни имени узла (подразумевая универсальный адрес), задаем номер порта 8888 и не указываем тип сокета.-рfreebsd % <b>testga -р -s 8888 -t stream</b>socket(AF_INET6, SOCK_STREAM, 6)address: [::]:8888socket(AF_INET, SOCK_STREAM, 6)address: 0.0.0.0:8888Возвращаются две структуры. Поскольку мы запустили эту программу на узле, поддерживающем и IPv4, и IPv6, не задав семейства адресов, функция
возвращает универсальный адрес IPv6 и универсальный адрес IPv4. Структура IPv6 возвращается перед структурой IPv4, поскольку, как мы увидим в главе 12, клиент или сервер IPv6 на узле с двойным стеком может взаимодействовать с собеседниками по IPv6 и по IPv4.getaddrinfo11.11. Функция host_serv
Наш первый интерфейс функции
не требует от вызывающего процесса размещать в памяти структуру рекомендаций и заполнять ее. Вместо этого аргументами нашей функцииgetaddrinfoбудут интересующие нас поля — семейство адресов и тип сокета.host_serv#include "unp.h"struct addrinfo *host_serv(const char *<i>hostname</i>, const char *<i>service</i>, int <i>family</i>, int <i>socktype</i>);<i>Возвращает: в случае успешного выполнения указатель на структуру addrinfo. NULL в случае ошибки</i>В листинге 11.3 показан исходный код этой функции.
Листинг 11.3. Функция host_serv
//lib/host_serv.c1 #include "unp.h"2 struct addrinfo*3 host_serv(const char *host, const char *serv, int family, int socktype)4 {5 int n;6 struct addrinfo hints, *res;7 bzero(&hints, sizeof(struct addrinfo));8 hints.ai_flags = AI_CANONNAME; /* всегда возвращает каноническое имя */9 hints.ai_family = family; /* AF_UNSPEC, AF_INET, AF_INET6, ... */