, и сама эта структура устроена так же. Логика функции зависит от аргумента
family
и параметра распознавателя
RES_USE_INET6
(который мы упомянули в конце предыдущего раздела).
Функция getipnodebyname
Документ RFC 2553 [38] запретил использование
RES_USE_INET6
и
gethostbyname2
из-за глобальности флага
RES_USE_INET6
и желания предоставить больше возможностей по управлению возвращаемыми сведениями. Для решения перечисленных проблем была предложена функция
getipnodebyname
.
#include <sys/socket.h>
#include <netdb.h>
struct hostent *getipnodebyname(const char * name, int af,
int flags, int * error_num);
Возвращает:
ненулевой указатель в случае успешного завершения, нулевой в случае ошибки
Функция возвращает указатель на ту же структуру
hostent
, которая использовалась
gethostbyname
. Аргументы
af
и
flags
непосредственно соответствуют полям
hints.ai_family
и
hints.ai_flags
. Для обеспечения безопасности в многопоточной среде возвращаемое значение выделяется динамически, поэтому его приходится освобождать вызовом
freehostent
.
#include <netdb.h>
void freehostent(struct hostent * ptr);
Функции
getipnodebyname
и
getipnodebyaddr
были отменены в RFC 3493 [36], а вместо них было предложено использовать
getaddrinfo
и
getnameinfo
.
11.21. Другая информация о сетях
В этой главе мы сфокусировали внимание на именах узлов, IP-адресах, именах и номерах портов служб. Если же обобщить полученную информацию, мы увидим, что существует четыре типа данных (имеющих отношение к сетям), которые могут понадобиться приложению: узлы, сети, протоколы и службы. В большинстве случаев происходит поиск данных, относящихся к узлам (функции
gethostbyname
и
gethostbyaddr
), реже — к службам (функции
getservbyname
и
getservbyaddr
) и еще реже — к сетям и протоколам.
Все четыре типа данных могут храниться в файле, и для каждого из четырех типов определены три функции:
1. Функция
get XXXent
, читающая следующую запись в файле, при необходимости открывающая файл.
2. Функция
set XXXent
, которая открывает файл (если он еще не открыт) и переходит к началу файла.
3. Функция
end XXXent
, закрывающая файл.
Для каждого из четырех типов данных определяется его собственная структура (соответственно, структуры
hostent
,
netent
,
protoent
и
servent
), что требует включения заголовка
<netdb.h>
.
В дополнение к трем функциям
get
,
set
и
end
, которые допускают последовательную обработку файла, для каждого из четырех типов данных предоставляются функции ключевого поиска, или поиска по ключу( keyed lookup). Эти функции последовательно проходят файл (вызывая функцию
get XXXent
для чтения каждой строки файла), но вместо того чтобы возвращать каждую строку вызывающему процессу, эти функции ищут элемент, совпадающий с аргументом. Имена функций поиска по ключу имеют вид
get XXXby YYY
. Например, две функции ключевого поиска для информации об узле — это функции
gethostbyname
(ищет элемент, совпадающий с именем узла) и
gethostbyaddr
(ищет элемент, совпадающий с IP-адресом). Таблица 11.5 обобщает эту информацию.
Таблица 11.5.
Четыре типа данных, относящихся к сетям
Тип данных
Файл
Структура
Функции поиска по ключу
Узлы
/etc/hosts
Hostent
gethostbyaddr, gethostbyname
Сети
/etc/networks
Netent
getnetbyaddr, getnetbyname
Протоколы
/etc/protocols
Protoent
getprotobyname, getprotobynumber
Службы
/etc/services
Servent
getservbyname, getservbyport
Как это применяется, если используется DNS? Прежде всего, с помощью DNS возможен доступ только к информации об узле и о сети. Информация о протоколе и службах всегда считывается из соответствующего файла. Ранее в этой главе мы отмечали (см. подраздел «Альтернативы DNS»), что в разных реализациях отличаются способы, с помощью которых администратор определяет, что именно использовать для получения информации об узле и сети — DNS или файл.
Далее, если DNS используется для получения информации об узле и о сети, имеют смысл только функции поиска по ключу. Используя, например, функцию
gethostent
, не стоит надеяться, что она выполнит последовательный перебор всех записей DNS! Если вызывается функция
gethostent
, она считывает только информацию об узлах и не использует DNS.
ПРИМЕЧАНИЕ
Хотя информацию о сети можно сделать доступной с помощью DNS, очень немногие пользуются этим. На с. 347-348 [1] рассказывается об этой возможности. Однако обычно администраторы создают и обслуживают файл /etc/networks, используемый вместо DNS. Программа netstat с параметром -i использует этот файл, если он есть, и выводит имя каждой сети. Однако бесклассовая адресация (см. раздел А.4) делает эти функции бесполезными, а поскольку они не поддерживают IPv6, новые приложения не должны использовать их.
11.22. Резюме
Набор функций, вызываемых приложением для преобразования имени узла в IP- адрес и обратно, называется распознавателем. Две функции,
gethostbyname
и
gethostbyaddr
, являются типичными точками входа. С переходом на IPv6 и многопоточное программирование полезными становятся
getaddrinfo
и
getnameinfo
, способные работать с адресами IPv6 и безопасные в многопоточной среде.
Для работы с именами служб и номерами портов широко используется функция
getservbyname
, принимающая имя службы и возвращающая структуру, содержащую номер порта. Преобразование чаще всего осуществляется на основании данных, содержащихся в некотором текстовом файле. Существует возможность сопоставления имен и номеров протоколов, а также имен и номеров сетей, но используется она реже.
Альтернативой DNS, которую мы не упомянули, является непосредственный вызов функций распознавателя вместо использования функций
gethostbyname
и
gethostbyaddr
. Таким способом пользуется, например, программа
sendmail
, предназначенная для поиска записи типа MX, чего не может сделать функция
gethostby XXX
. У функций распознавателя имена начинаются с
res_
. Примером такой функции является функция
res_init
, которую мы описали в разделе 11.4. Описание этих функций и пример вызывающей их программы находятся в главе 15 книги [1]. При вводе в командной строке man
resolver
должны отобразиться страницы руководства для этих функций.
Упражнения
1. Измените программу, представленную в листинге 11.1, так, чтобы для каждого возвращаемого адреса вызывалась функция
gethostbyaddr
, а затем выведите возвращаемое имя
h_name
. Сначала запустите программу, задав имя узла только с одним IP-адресом, а затем — с несколькими IP-адресами. Что происходит?
2. Устраните проблему, показанную в предыдущем упражнении.
3. Запустите программу, показанную в листинге 11.4, задав имя службы