getaddrinfo_a(3) | Library Functions Manual | getaddrinfo_a(3) |
getaddrinfo_a, gai_suspend, gai_error, gai_cancel - асинхронная трансляция сетевого адреса и службы
Asynchronous name lookup library (libanl, -lanl)
#define _GNU_SOURCE /* См. feature_test_macros(7) */ #include <netdb.h>
int getaddrinfo_a(int mode, struct gaicb *list[restrict], int nitems, struct sigevent *restrict sevp); int gai_suspend(const struct gaicb *const list[], int nitems, const struct timespec *timeout);
int gai_error(struct gaicb *req); int gai_cancel(struct gaicb *req);
Функция getaddrinfo_a() выполняет ту же задачу что и getaddrinfo(3), но позволяет выполнять поиск нескольких имён асинхронно, с дополнительным уведомлением о завершении операций поиска.
В аргументе mode указывается одно из следующих значений:
В массиве list задаются запросы на обработку. В аргументе nitems задаётся количество элементов в list. Запрашиваемые операции поиска начинаются параллельно. Элементы NULL в списке list игнорируются. Каждый запрос описывается структурой gaicb, которая определена следующим образом:
struct gaicb { const char *ar_name; const char *ar_service; const struct addrinfo *ar_request; struct addrinfo *ar_result; };
Элементы данной структуры совпадают с аргументами getaddrinfo(3). То есть ar_name соответствует аргументу node, а ar_service аргументу service (определяют узел Интернета и службу). Элемент ar_request соответствует аргументу hints; им задаётся критерий выбора структуры возвращаемого адреса сокета. И, наконец, ar_result соответствует аргументу res; вам не нужно инициализировать этот элемент, он будет заполнен автоматически в результате запроса. Структура addrinfo, на которую ссылаются последние два элемента, описана в getaddrinfo(3).
Если значение mode равно GAI_NOWAIT, то уведомления о обработанных запросах можно получить из структуры sigevent, на которую указывает аргумент sevp. Определение и описание данной структуры приведено в sigevent(7). Поле sevp->sigev_notify может иметь следующие значения:
При SIGEV_SIGNAL и SIGEV_THREAD, может быть полезно, чтобы sevp->sigev_value.sival_ptr указывала на list.
Функция gai_suspend() приостанавливает выполнение вызывающей нити, ожидая завершения поиска одного или более запросов из массива list. В аргументе nitems задаётся размер массива list. Вызов блокирует выполнение пока не произойдёт одно из следующего:
При выполнении явно не указывается какие запросы завершены; для определения вам нужно обойти весь список запросов с помощью gai_error().
Функция gai_error() возвращает состояние запроса req: EAI_INPROGRESS — запрос пока не выполнен, 0 — обработан успешно, код ошибки — запрос невозможно обработать.
Функция gai_cancel() отменяет запрос req. При успешной отмене состояние ошибки устанавливается в EAI_CANCELED и выполняется обычное асинхронное уведомление. Запрос не может быть отменён, если он начал обрабатываться; в этом случае действие будет доведено до конца, как если бы вызова gai_cancel() не происходило. Если req равно NULL, то будет предпринята попытка отменить все имеющиеся запросы.
Функция getaddrinfo_a() возвращает 0, если все запросы были успешно обработаны или один из следующих ненулевых кодов ошибки:
Функция gai_suspend() возвращает 0, если завершён хотя бы один из запросов. В противном случае возвращается один из следующих ненулевых кодов ошибки:
Функция gai_error() может вернуть EAI_INPROGRESS для незаконченных запросов поиска, 0 при успешном поиске (как описано выше), один из кодов ошибок, которые может вернуть getaddrinfo(3) или код ошибки EAI_CANCELED, если запрос был отменён явно до завершения.
Функция gai_cancel() может вернуть одно из следующих значений:
Функция gai_strerror(3) транслирует эти коды ошибок в читаемый формат, подходящий для сообщений об ошибке.
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение |
getaddrinfo_a(), gai_suspend(), gai_error(), gai_cancel() | Безвредность в нитях | MT-Safe |
These functions are GNU extensions; they first appeared in glibc 2.2.3.
Интерфейс getaddrinfo_a() был создан после интерфейса lio_listio(3).
Вот два примера: простой пример выполнения нескольких запросов синхронно одновременно, и сложный пример, показывающий асинхронные возможности.
Эта программа определяет несколько имён узлов параллельно, что быстрее по сравнению с определением имён последовательно с помощью getaddrinfo(3). Результат работы программы:
$ ./a.out mirrors.kernel.org enoent.linuxfoundation.org gnu.org mirrors.kernel.org: 139.178.88.99 enoent.linuxfoundation.org: Name or service not known gnu.org: 209.51.188.116
Исходный код программы
#define _GNU_SOURCE #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { int ret; struct gaicb *reqs[argc - 1]; char host[NI_MAXHOST]; struct addrinfo *res; if (argc < 2) { fprintf(stderr, "Использование: %s УЗЕЛ...\n", argv[0]); exit(EXIT_FAILURE); } for (size_t i = 0; i < argc - 1; i++) { reqs[i] = malloc(sizeof(*reqs[0])); if (reqs[i] == NULL) { perror("malloc"); exit(EXIT_FAILURE); } memset(reqs[i], 0, sizeof(*reqs[0])); reqs[i]->ar_name = argv[i + 1]; } ret = getaddrinfo_a(GAI_WAIT, reqs, argc - 1, NULL); if (ret != 0) { fprintf(stderr, "ошибка getaddrinfo_a(): %s\n", gai_strerror(ret)); exit(EXIT_FAILURE); } for (size_t i = 0; i < argc - 1; i++) { printf("%s: ", reqs[i]->ar_name); ret = gai_error(reqs[i]); if (ret == 0) { res = reqs[i]->ar_result; ret = getnameinfo(res->ai_addr, res->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST); if (ret != 0) { fprintf(stderr, "getnameinfo() failed: %s\n", gai_strerror(ret)); exit(EXIT_FAILURE); } puts(host); } else { puts(gai_strerror(ret)); } } exit(EXIT_SUCCESS); }
Данный пример — простая интерактивная оболочка к getaddrinfo_a(). Возможности уведомления не используются.
Результат работы программы:
$ ./a.out > a mirrors.kernel.org enoent.linuxfoundation.org gnu.org > c 2 [2] gnu.org: Request not canceled > w 0 1 [00] mirrors.kernel.org: Finished > l [00] mirrors.kernel.org: 139.178.88.99 [01] enoent.linuxfoundation.org: Processing request in progress [02] gnu.org: 209.51.188.116 > l [00] mirrors.kernel.org: 139.178.88.99 [01] enoent.linuxfoundation.org: Name or service not known [02] gnu.org: 209.51.188.116
Исходный код программы:
#define _GNU_SOURCE #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> static struct gaicb **reqs = NULL; static size_t nreqs = 0; static char * getcmd(void) { static char buf[256]; fputs("> ", stdout); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) return NULL; if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = 0; return buf; } /* Add requests for specified hostnames. */ static void add_requests(void) { size_t nreqs_base = nreqs; char *host; int ret; while ((host = strtok(NULL, " "))) { nreqs++; reqs = realloc(reqs, sizeof(reqs[0]) * nreqs); reqs[nreqs - 1] = calloc(1, sizeof(*reqs[0])); reqs[nreqs - 1]->ar_name = strdup(host); } /* очередь запросов nreqs_base..nreqs. */ ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base], nreqs - nreqs_base, NULL); if (ret) { fprintf(stderr, "ошибка getaddrinfo_a(): %s\n", gai_strerror(ret)); exit(EXIT_FAILURE); } } /* Wait until at least one of specified requests completes. */ static void wait_requests(void) { char *id; int ret; size_t n; struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs)); /* NULL elements are ignored by gai_suspend(). */ while ((id = strtok(NULL, " ")) != NULL) { n = atoi(id); if (n >= nreqs) { printf("Неправильный номер запроса: %s\n", id); return; } wait_reqs[n] = reqs[n]; } ret = gai_suspend(wait_reqs, nreqs, NULL); if (ret) { printf("gai_suspend(): %s\n", gai_strerror(ret)); return; } for (size_t i = 0; i < nreqs; i++) { if (wait_reqs[i] == NULL) continue; ret = gai_error(reqs[i]); if (ret == EAI_INPROGRESS) continue; printf("[%02zu] %s: %s\n", i, reqs[i]->ar_name, ret == 0 ? "Finished" : gai_strerror(ret)); } } /* Cancel specified requests. */ static void cancel_requests(void) { char *id; int ret; size_t n; while ((id = strtok(NULL, " ")) != NULL) { n = atoi(id); if (n >= nreqs) { printf("Неправильный номер запроса: %s\n", id); return; } ret = gai_cancel(reqs[n]); printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name, gai_strerror(ret)); } } /* List all requests. */ static void list_requests(void) { int ret; char host[NI_MAXHOST]; struct addrinfo *res; for (size_t i = 0; i < nreqs; i++) { printf("[%02zu] %s: ", i, reqs[i]->ar_name); ret = gai_error(reqs[i]); if (!ret) { res = reqs[i]->ar_result; ret = getnameinfo(res->ai_addr, res->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST); if (ret) { fprintf(stderr, "ошибка getnameinfo(): %s\n", gai_strerror(ret)); exit(EXIT_FAILURE); } puts(host); } else { puts(gai_strerror(ret)); } } } int main(void) { char *cmdline; char *cmd; while ((cmdline = getcmd()) != NULL) { cmd = strtok(cmdline, " "); if (cmd == NULL) { list_requests(); } else { switch (cmd[0]) { case 'a': add_requests(); break; case 'w': wait_requests(); break; case 'c': cancel_requests(); break; case 'l': list_requests(); break; default: fprintf(stderr, "Bad command: %c\n", cmd[0]); break; } } } exit(EXIT_SUCCESS); }
getaddrinfo(3), inet(3), lio_listio(3), hostname(7), ip(7), sigevent(7)
Русский перевод этой страницы руководства был сделан Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitry Bolkhovskikh <d20052005@yandex.ru>, Vladislav <ivladislavefimov@gmail.com>, Yuri Kozlov <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>
Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.
Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.
5 февраля 2023 г. | Linux man-pages 6.03 |