UNIX: разработка сетевых приложений
Таблица 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 используется для получения информации об узле и о сети, имеют смысл только функции поиска по ключу. Используя, например, функцию
, не стоит надеяться, что она выполнит последовательный перебор всех записей DNS! Если вызывается функцияgethostent, она считывает только информацию об узлах и не использует DNS.gethostentПРИМЕЧАНИЕХотя информацию о сети можно сделать доступной с помощью DNS, очень немногие пользуются этим. На с. 347-348 [1] рассказывается об этой возможности. Однако обычно администраторы создают и обслуживают файл /etc/networks, используемый вместо DNS. Программа netstat с параметром -i использует этот файл, если он есть, и выводит имя каждой сети. Однако бесклассовая адресация (см. раздел А.4) делает эти функции бесполезными, а поскольку они не поддерживают IPv6, новые приложения не должны использовать их.
11.22. Резюме
Набор функций, вызываемых приложением для преобразования имени узла в IP- адрес и обратно, называется распознавателем. Две функции,
иgethostbyname, являются типичными точками входа. С переходом на IPv6 и многопоточное программирование полезными становятсяgethostbyaddrиgetaddrinfo, способные работать с адресами IPv6 и безопасные в многопоточной среде.getnameinfoДля работы с именами служб и номерами портов широко используется функция
, принимающая имя службы и возвращающая структуру, содержащую номер порта. Преобразование чаще всего осуществляется на основании данных, содержащихся в некотором текстовом файле. Существует возможность сопоставления имен и номеров протоколов, а также имен и номеров сетей, но используется она реже.getservbynameАльтернативой DNS, которую мы не упомянули, является непосредственный вызов функций распознавателя вместо использования функций
иgethostbyname. Таким способом пользуется, например, программаgethostbyaddr, предназначенная для поиска записи типа MX, чего не может сделать функцияsendmail. У функций распознавателя имена начинаются сgethostby<i>XXX</i>. Примером такой функции является функцияres_, которую мы описали в разделе 11.4. Описание этих функций и пример вызывающей их программы находятся в главе 15 книги [1]. При вводе в командной строке manres_initдолжны отобразиться страницы руководства для этих функций.resolverУпражнения
1. Измените программу, представленную в листинге 11.1, так, чтобы для каждого возвращаемого адреса вызывалась функция
, а затем выведите возвращаемое имяgethostbyaddr. Сначала запустите программу, задав имя узла только с одним IP-адресом, а затем — с несколькими IP-адресами. Что происходит?h_name2. Устраните проблему, показанную в предыдущем упражнении.
3. Запустите программу, показанную в листинге 11.4, задав имя службы
.chargen4. Запустите программу, показанную в листинге 11.4, задав IP-адрес в точечно- десятичной записи в качестве имени узла. Допускает ли это ваш распознаватель? Измените листинг 11.4, чтобы разрешить IP-адрес в виде строки десятичных чисел с точками в качестве имени узла и строку с десятичным номером порта в качестве имени службы. В каком порядке должно выполняться тестирование IP-адреса для строки в точечно-десятичной записи и для имени?
5. Измените программу в листинге 11.4 так, чтобы можно было работать либо с IPv4, либо с IPv6.
6. Измените программу в листинге 8.5 так, чтобы сделать запрос DNS, и сравните возвращаемый IP-адрес со всеми IP-адресами узла получателя, то есть вызовите функцию
, используя IP-адрес, возвращаемый функциейgethostbyaddr, а затем вызовитеrecvfromдля поиска всех IP-адресов для узла.gethostbyname7. Измените листинг 11.6, чтобы вызвать функцию
вместо функцииgetnameinfo. Какие флаги вы должны передать функцииsock_ntop?getnameinfo8. В разделе 7.5 мы обсуждали завладение портом с помощью параметра сокета
. Чтобы увидеть, как это происходит, создайте не зависящий от протокола сервер времени и даты UDP, показанный в листинге 11.13. Запустите один экземпляр сервера в одном окне, свяжите его с универсальным адресом и некоторым портом, который вы выберете. Запустите в другом окне клиент и убедитесь, что этот сервер выполняет обработку клиента (отметьте вызов функцииSO_REUSEADDRна узле сервера). Затем запустите другой экземпляр сервера в другом окне, и на этот раз свяжите его с одним из адресов направленной передачи узла и тем же портом, что и первый сервер. С какой проблемой вы сразу же столкнетесь? Устраните эту проблему и перезапустите второй сервер. Запустите клиент, отправьте дейтаграмму и проверьте, что второй сервер захватил порт первого сервера. Если возможно, запустите второй сервер снова с учетной записью, отличной от учетной записи первого сервера, чтобы проверить, происходит ли по-прежнему захват порта, поскольку некоторые производители не допускают второго связывания, если идентификатор пользователя отличен от идентификатора процесса, уже связанного с портом.printf9. В конце раздела 2.12 мы показали два примера Telnet: сервер времени и даты и эхо-сервер. Зная, что клиент проходит через два этапа — функцию
и функцию connect, определите, к каким этапам относятся строки вывода клиента.gethostbyname