Определение ip-адреса по имени хоста, adns
Есть такой, характерный для организации "традиционного" UNIX'а,
системный вызов под названием struct hostent * gethostbyname(const char *name);
Традиционен он
тем, что его нельзя использовать в многопоточных программах по той причине,
что два параллельных обращения к Собственно, обычно, для того, что бы получить IP-адрес по DNS-имени, используют именно этот вызов. Его недостатками являются уже упомянутая выше не "реентерабельность" (это английское слово, судя по всему, стало термином), отсутствие возможности определения адреса хоста, соответствующему иному протоколу, чем IPv4 и... низкая производительность, как это ни странно. Надо понимать, что DNS, кроме самих серверов, включает в себя еще и протокол передачи данных, который принципиально ничем не отличается от других (того же HTTP). В предыдущей заметке в этом разделе я уже говорил о том, что программа, выкачивающая один файл, отличается от программы, которая выкачивает несколько файлов. Тоже самое и с обращениями к DNS-серверам: если "разрешение" одного хоста произойдет достаточно быстро (относительно), то в случае с большим количеством хостов все уже не так радужно.
То есть, программа, которая качает одновременно несколько
файлов, должна управляться событиями ввода-вывода: как конкретно
она это будет делать, не особенно интересно, но все дело в том,
что использование любых операций, блокирующих процесс,
могут свести на нет все усилия по обеспечению параллельности запросов.
В тоже самое время,
Вообще говоря, конечно же, можно как-то попытаться ускорить процесс. Например,
перед тем, как обратиться к DNS-серверу, В случае, когда все хосты известны заранее, можно разбить программу на две части: сначала происходит разрешение имен, а затем --- выкачивание информации. Но, если честно, это не выход.
Более логичное решение заключается в том, что, если программа
управляется событиями ввода-вывода, то надо добавить сюда
еще и события "определения IP-адреса". Это уже
предполагает то, что
select()),
а под какое-то определение IP-адреса приходится либо еще потоки
запускать, либо, как это делает webalaizer, несколько дочерних
процесоов создавать. В то же самое время, многопоточная программа
много сложнее однопоточной и совсем не факт, что преимущества
относительно быстрого и неблокирующего определения IP-адресов
покроет все усилия, связанные с синхронизацией потоков.
При этом учтите и то, что тот факт, что многопоточная программа
нормально работает на компьютере с одним процессором, совсем не означает,
что она так же нормально будет работать на компьютере с несколькими процессорами.
Теперь, возвращаясь к, собственно, теме сегодняшней заметки. ADNS. Это
такой пакет, в который входит библиотека с заголовочными файлами и несколько
утилит, которые можно использовать в скриптах. Среди ее преимуществ, кроме того,
что она исключает существенные недостатки В принципе, ADNS так же не является "реентерабельной". Но ее скорость работы, вообще говоря, снимает проблемы с необходимостью в "реентарабельности" функций. Документация к ADNS есть только одна: внутри заголовочного файла. Зная о нелюбви русского программиста читать даже хорошо оформленную документацию, на этот раз приведу кусок простейшей программы, которая с этим ADNS работает. На самом деле, приведенной функциональности хватит для большинства приложений.
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#include <adns.h>
int main(int argc, char* argv[])
{
struct sigaction sigpipe, sigpipeo;
sigemptyset(&sigpipe.sa_mask);
sigpipe.sa_flags = SA_RESTART;
sigpipe.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sigpipe, &sigpipeo);
adns_state ads = NULL;
/*
* Инициализация ADNS.
*/
adns_init(&ads, adns_if_nosigpipe, 0);
// ...
/*
* Осуществляем все запросы к ADNS. В данном случае ---
* пачкой и сразу, но можно и в процессе обработки.
*/
for( ; ; )
{
// ...
adns_query aquery = 0;
/*
* А вот документацию на эту функцию, скорее
* всего, посмотреть придется, потому что тут
* надо указать флаги, характеризующие то, что
* вы хотите от ADNS получить. Под hostname
* понимается название хоста.
*/
adns_submit(ads, hostname,
(adns_rrtype)adns_r_addr,
(adns_queryflags)adns_qf_owner,
0,
&aquery);
// ...
}
/*
* Теперь все запросы поданы, надо обработать
* результаты. В данном случае, запрос _ожидается_.
* Но можно и просто проверять наличие выполненных
* запросов.
*/
for( ; ; )
{
adns_answer* answer = NULL;
adns_query query = NULL;
adns_wait_poll(ads, &query, &answer, NULL);
if(!answer) break;
if(answer->status == adns_s_ok)
{
/*
* Ответ получен. Теперь в answer находится то,
* что вы "заказали" при submit'е. В данном
* случае имеют интерес поля answer->owner,
* answer->rrs и answer->nrrs.
*/
}
}
/*
* Завершение работы. Об этом надо сказать ADNS.
*/
adns_finish(ads);
return 0;
}
Ресолвер очень быстрый. Желающие могут написать маленькую итеративную программу с использованием
Резюме
Использование
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
© 2000-2008, Andrey L. Kalinin mailto:andrey@kalinin.ru |
|