UNIX: разработка сетевых приложений
Разница между функциями
иsock_ntopсостоит в том, что первая не задействует DNS, а только возвращает IP-адрес и номер порта. Последняя же обычно пытается получить имя и для узла, и для службы.getnameinfoВ табл. 11.4 показаны шесть флагов, которые можно задать для изменения действия, выполняемого функцией
.getnameinfoТаблица 11.4. Флаги функции getnameinfo
Константа Описание NI_DGRAM Дейтаграммный сокет NI_NAMEREQD Возвращать ошибку, если невозможно получить имя узла по его адресу NI_NOFQDN Возвращать только ту часть FQDN, которая содержит имя узла NI_NUMERICHOST Возвращать численное значение адреса вместо имени узла NI_NUMERICSCOPE Возвращать численное значение идентификатора области NI_NUMERICSERV Возвращать номер порта вместо имени службы ■ Флаг
должен быть задан, когда вызывающий процесс знает, что работает с дейтаграммным сокетом. Причина в том, что если функцииNI_DGRAMзадать только IP-адрес и номер порта в структуре адреса сокета, она не сможет определить протокол (TCP или UDP). Существует несколько номеров портов, которые в случае TCP задействованы для одной службы, а в случае UDP для совершенно другой. Примером может служить порт 514, используемый службойgetnameinfoв TCP и службойrshв UDP.syslog■ Флаг
приводит к возвращению ошибки, если имя узла не может быть разрешено при использовании DNS. Этот флаг может использоваться серверами, которым требуется, чтобы IP-адресу клиента было сопоставлено имя узла. Затем эти серверы получают возвращаемое имя узла, вызывают функциюNI_NAMEREQDи проверяют, совпадают ли результаты вызова этих двух функций хотя бы частично.gethostbyname■ Флаг
вызывает сокращение имени узла, отбрасывая все, что идет после первой точки. Например, если в структуре адреса сокета содержится IP-адрес 192.168.42.2, то функцияNI_NOFQDNвозвратит имяgethostbyaddr. Но если в функцииaix.unpbook.comзадан флагgetnameinfo, она возвратит в имени узла толькоNI_NOFQDN.aix■ Флаг
сообщает функцииNI_NUMERICHOST, что не нужно вызывать DNS (поскольку это занимает некоторое время). Вместо этого возвращается численное представление IP-адреса, вероятно, при помощи вызова функцииgetnameinfo. Аналогично, флагinet_ntopопределяет, что вместо имени службы должен быть возвращен десятичный номер порта. Обычно серверы должны задавать этот флаг, поскольку номера портов клиента, как правило, не имеют соответствующего имени службы — это динамически назначаемые порты.NI_NUMERICSERVуказывает на необходимость возвращения идентификатора области в численном, а не в текстовом виде.NI_NUMERICSCOPEМожно объединять несколько флагов путем логического сложения, если их сочетание имеет смысл, например
иNI_DGRAM.NI_NUMERICHOST11.18. Функции, допускающие повторное вхождение
Функция
из раздела 11.3 имеет интересную особенность, которую мы еще не рассматривали: она не допускает повторное вхождение (nonreentrant). Мы еще столкнемся с этой проблемой в главе 23, когда будем обсуждать потоки, но не менее интересно найти решение этой проблемы сейчас, без необходимости обращаться к понятию потоков.gethostbynameСначала посмотрим, как эта функция работает. Если мы изучим ее исходный код (это несложно, поскольку исходный код для всей реализации BIND свободно доступен), то увидим, что обе функции — и
, иgethostbyname— содержатся в одном файле, который имеет следующий вид:gethostbyaddr<b>static</b> struct hostent host; /* здесь хранится результат */struct hostent*gethostbyname(const char *hostname) {return(gethostbyname2(hostname, family));}struct hostent*gethostbyname2(const char *hostname, int family) {/* вызов функций DNS для запроса А или AAAA *//* заполнение структуры адреса узла */return(&host);}struct hostent*gethostbyaddr(const char *addr, size_t len, int family) {/* вызов функций DNS для запроса PTR в домене in-addr.arpa *//* заполнение структуры адреса узла */return(&host);}Мы выделили полужирным шрифтом спецификатор класса памяти
итоговой структуры, потому что основная проблема в нем. Тот факт, что эти три функции используют общую переменнуюstatic, представляет другую проблему, которую мы обсудим в упражнении 11.1. (Вспомните табл. 11.4.) Функцияhostпоявилась в BIND 4.9.4 с добавлением поддержки IPv6. Мы будем игнорировать тот факт, что когда мы вызываем функциюgethostbyname2, задействуется функцияgethostbyname, поскольку это не относится к предмету обсуждения.gethostbyname2Проблема повторного вхождения может возникнуть в нормальном процессе Unix, вызывающем функцию
илиgethostbynameи из управляющего элемента главного потока, и из обработчика сигнала. Когда вызывается обработчик сигнала (допустим, это сигналgethostbyaddr, который генерируется раз в секунду), главный поток управляющего элемента процесса временно останавливается и вызывается функция обработки сигнала. Рассмотрим следующую ситуацию:SIGALRMmain() {