KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программное обеспечение » Уильям Стивенс - UNIX: разработка сетевых приложений

Уильям Стивенс - UNIX: разработка сетевых приложений

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Уильям Стивенс, "UNIX: разработка сетевых приложений" бесплатно, без регистрации.
Перейти на страницу:

Мы не используем в примерах книги записей типа MX, но упоминаем о них, потому что они широко используются в реальной жизни.

■ CNAME. Аббревиатура CNAME означает «каноническое имя» (canonical name). Обычно такие записи используются для присвоения имен распространенным службам, таким как ftp и www. При использовании имен служб вместо действительного имени узла перемещение службы на другой узел становится прозрачным (то есть незаметным для пользователя). Например, для нашего узла linux каноническими именами могут быть следующие записи:

ftp IN CNAME linux.unpbook.com.

www IN CNAME linux.unpbook.com.

Сейчас прошло еще слишком мало времени с момента появления протокола IPv6, чтобы сказать, каких соглашений будут придерживаться администраторы для узлов, поддерживающих и IPv4, и IPv6. В нашем примере мы задали узлу freebsd и запись типа А, и запись типа AAAA. Автор помещает и запись типа А, и запись типа AAAA под каноническим именем узла (как показано ниже) и создает три записи RR. Первая запись RR, имя которой оканчивается на -4, содержит запись типа А; вторая, с именем, оканчивающимся на -6, содержит запись типа AAAA; а третья запись RR, имя которой оканчивается на -611, содержит запись типа AAAA с локальным в пределах физической подсети (link-local, см. главу 19) адресом узла (что иногда удобно использовать в целях отладки). Все записи для другого нашего узла будут выглядеть так:

aix-4   IN А    206.62.226.43

aix     IN А    206.62.226.43

        IN MX   5 aix.unpbook.com.

        IN MX   10 mailhost.unpbook.com.

Aix-4   IN A    192.168.42.2

aix-6   IN AAAA 3ffe:b80:1f8d:2:204:acff:fe17:bf38

aix-611 IN AAAA fe80::204:acff:fe17:bf38

Эта запись дает нам дополнительный контроль над протоколом, выбранным некоторыми приложениями, как мы увидим в следующей главе.

Распознаватели и серверы имен

Организации обычно работают с одним или несколькими серверами имен (name servers). Часто в качестве сервера используется программа BIND (Berkeley Internet Name Domain). Приложения, такие как клиенты и серверы, которые мы создаем в этой книге, соединяются с сервером DNS при помощи вызова функций из библиотеки, называемой распознавателем (resolver). Обычные функции распознавателя — gethostbyname и gethostbyaddr, и обе они описаны в этой главе. Первая находит адрес узла по его имени, а вторая — наоборот.

На рис. 11.1 показано типичное расположение приложений, распознавателей и серверов имен. В некоторых системах код распознавателя содержится в системной библиотеке и встраивается в приложение, когда оно создается. В других системах имеется централизованный демон-распознаватель, к которому обращаются все приложения. Системная библиотека выполняет удаленные вызовы процедур такого распознавателя. В любом случае код приложения вызывает код распознавателя посредством обычных вызовов, чаще всего gethostbyname и gethostbyaddr.

Рис. 11.1. Типичное расположение приложений, распознавателей и серверов имен

Код распознавателя считывает из файлов конфигурации, зависящих от системы, расположение серверов имен организации. (Мы говорим «серверы имен», употребляя множественное число, потому что большинство организаций работают с несколькими серверами имен, хотя мы и показываем на рисунке только один локальный сервер.) Файл /etc/resolv.conf обычно содержит IP-адреса локальных серверов имен.

ПРИМЕЧАНИЕ

Было бы удобно указывать в файле /etc/resolv.conf имена, а не IP-адреса серверов имен, потому что имена удобнее запоминать и редактировать, однако это возвратило бы нас к вечной проблеме курицы и яйца: каким образом распознать имя сервера имен?

Распознаватель посылает запрос локальному серверу имен, используя UDP. Если локальный сервер имен не знает ответа, он обычно запрашивает другие серверы имен через Интернет, также используя UDP. Если ответ слишком велик, чтобы поместиться в один UDP-пакет, распознаватель автоматически переключается на TCP.


Альтернативы DNS

Можно получить информацию об имени и адресе без использования DNS. Типичной альтернативой служат статические файлы со списком узлов (обычно файл /etc/hosts, как мы указываем в табл. 11.2), информационная система сети (Network Information System, NIS) и упрощенный протокол службы каталогов (Lightweight Directory Access Protocol — LDAP). К сожалению, способ конфигурирования узла для использования различных типов служб имен зависит от реализации. Solaris 2.x, HP-UX 10 и более новых версий, а также FreeBSD 5.x используют файл /etc/nswitch.conf, тогда как AIX использует файл /etc/netsvc.conf. BIND 9.9 предоставляет свою собственную версию, которая называется IRS (Information Retrieval Service — служба получения информации), использующую файл /etc/irs.conf. Если сервер имен должен применяться для поиска имен узлов, все эти системы используют для задания IP-адресов серверов имен файл /etc/resolv.conf. К счастью, эти различия обычно скрыты от программиста приложений, поэтому мы просто вызываем функции распознавателя, такие как gethostbyname и gethostbyaddr.

11.3. Функция gethostbyname

Узлы компьютерных сетей мы обычно идентифицируем по их именам, удобным для человеческого восприятия. Но во всех примерах книги специально использовались IP-адреса вместо имен, поэтому мы точно знаем, что входит в структуры адресов сокетов для таких функций, как connect и sendto, и что возвращается функциями accept и recvfrom. Тем не менее большинство приложений имеют дело с именами, а не с адресами. Это особенно актуально при переходе на IPv6, поскольку адреса IPv6 (шестнадцатеричные строки) значительно длиннее адресов IPv4, записанных в точечно-десятичном представлении. (Например, запись типа AAAA и запись типа PTR для ip6.arpa в предыдущем разделе показывают это со всей очевидностью.)

Самая основная функция, выполняющая поиск имени узла, — это функция gethostbyname. При успешном выполнении она возвращает указатель на структуру hostent, содержащую все адреса IPv4 для узла. Однако она может возвращать только адреса IPv4. В разделе 11.6 рассматривается функция, возвращающая адреса IPv4 и IPv6. Стандарт POSIX предупреждает, что функция gethostbyname может быть исключена из будущей его версии.

ПРИМЕЧАНИЕ

Маловероятно, что реализации gethostbyname исчезнут раньше, чем весь Интернет перейдет на протокол IPv6, а произойдет это еще очень не скоро. Однако удаление функции из стандарта POSIX гарантирует, что она не будет использоваться в новых программах. Вместо нее мы рекомендуем использовать getaddrinfo (раздел 11.6).

#include <netdb.h>


struct hostent *gethostbyname(const char *hostname);

Возвращает: непустой указатель в случае успешного выполнения, -1 в случае ошибки

Непустой указатель, возвращаемый этой функцией, указывает на следующую структуру hostent:

struct hostent {

 char *h_name;        /* официальное (каноническое) имя узла */

 char **h_alihases;   /* указатель на массив указателей на псевдонимы */

 int   h_addrtype;    /* тип адреса узла: AF_INET */

 int   h_length;      /* длина адреса: 4 */

 char  **h_addr_list; /* указатель на массив указателей с адресами IPv4 или IPv6 */

};

В терминах DNS функция gethostbyname выполняет запрос на запись типа А. Функция возвращает только адреса IPv4.

На рис. 11.2 представлено устройство структуры hostent и содержащаяся в ней информация, в предположении, что искомое имя узла имеет два альтернативных имени и три адреса IPv4. Все имена узла представляют собой строки языка С.

Рис. 11.2. Структура hostent и ее одержимое

Возвращаемое имя h_name называется каноническим именем узла. Например, с показанными в предыдущем разделе записями CNAME каноническое имя узла ftp://ftp.unpbook.com будет иметь вид linux.unpbook.com. Также если мы вызываем функцию gethostbyname с узла aix с неполным именем, например solaris, то в качестве канонического имени возвращается полное доменное имя (FQDN) solaris.unpbook.com..

ПРИМЕЧАНИЕ

Некоторые версии функции gethostbyname допускают, что аргумент hostname может быть записан в виде строки десятичных чисел, разделенных точками. То есть вызов в форме hptr = gethostbyname("206.62.226.33"); будет работать. Этот код был добавлен, поскольку клиент Rlogin принимает только имя узла, вызывая функцию gethostbyname, и не принимает точечно-десятичную запись [127]. Стандарт POSIX допускает это, но не устанавливает такое поведение в качестве обязательного, поэтому переносимое приложение не может использовать указанную особенность.


Функция gethostbyname отличается от других функций сокетов, описанных нами, тем, что она не задает значение переменной errno, когда происходит ошибка. Вместо этого она присваивает глобальной целочисленной переменной h_errno одну из следующих констант, определяемых в заголовке <netdb.h>:

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*