ИМЯ
getaddrinfo, freeaddrinfo, gai_strerror - трансляция сетевого адреса и службыLIBRARY
Standard C library ( libc, -lc)СИНТАКСИС
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h>
int getaddrinfo(const char *restrict node, const char *restrict service, const struct addrinfo *restrict hints, struct addrinfo **restrict res);
void freeaddrinfo(struct addrinfo *res);
const char *gai_strerror(int errcode);
Требования
макроса
тестирования
свойств
для glibc (см.
feature_test_macros(7)):
getaddrinfo(), freeaddrinfo(), gai_strerror():
Since glibc 2.22: _POSIX_C_SOURCE >= 200112L glibc 2.21 and earlier: _POSIX_C_SOURCE
ОПИСАНИЕ
По заданным node и service, определяющим узел и службу Интернета, getaddrinfo() возвращает одну или несколько структур addrinfo, каждая из которых содержит Интернет-адрес, который можно передавать в вызов bind(2) или connect(2). Функция getaddrinfo() объединяет возможности, предоставляемые функциями gethostbyname(3) и getservbyname(3) в одном интерфейсе, но в отличие от этих функций, getaddrinfo() реентерабельна и позволяет программам не зависеть от IPv4 или IPv6. Структура addrinfo, используемая в getaddrinfo(), содержит следующие поля:struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; struct sockaddr *ai_addr; char *ai_canonname; struct addrinfo *ai_next; };
Аргумент hints указывает на структуру addrinfo, которая определяет критерии выбора структур адреса сокета, возвращаемых в списке, указанном в res. Если hints не является NULL, то он указывает на структуру addrinfo. В ней с помощью ai_family, ai_socktype и ai_protocol определяются критерии, ограничивающие набор адресов сокета, возвращаемых getaddrinfo():
- ai_family
- Это поле определяет предпочитаемое семейство адресов для возвращаемых адресов. Правильными значениями для данного поля могут быть AF_INET и AF_INET6. Значение AF_UNSPEC отображает, что getaddrinfo() должна возвращать адреса сокета для любого семейства адресов (например, либо IPv4, либо IPv6), которые в дальнейшем могут быть использованы вместе с node и service.
- ai_socktype
- Это поле определяет предпочитаемы тип сокета, например, SOCK_STREAM или SOCK_DGRAM. Если в этом поле указан 0, то это означает, что getaddrinfo() может вернуть адреса сокета любого типа.
- ai_protocol
- Это поле определяет протокол для возвращаемых адресов сокета. Если в этом поле указан 0, то это означает, что getaddrinfo() может вернуть адрес сокета с любым протоколом.
- ai_flags
- В этом поле задаются дополнительные параметры, описываемые ниже. Несколько флагов указываются с логическим ИЛИ.
- •
- В полях ai_family, ai_socktype и ai_protocol возвращаются параметры создания сокета (т. е., эти поля имеют те же значения, что и соответствующие аргументы в socket(2)). Например, в ai_family может вернуться AF_INET или AF_INET6; в ai_socktype может вернуться SOCK_DGRAM или SOCK_STREAM; в ai_protocol возвращается протокол сокета.
- •
- Указатель на адрес сокета помещается в поле ai_addr, а длина адреса сокета (в байтах) помещается в поле ai_addrlen.
Расширения getaddrinfo() для интернациональных доменных имён
Начиная с glibc 2.3.4, getaddrinfo() был расширен для выборочного прозрачного разрешения исходящих и входящих адресов в формате интернациональных доменных имен (IDN, см. RFC 3490, Internationalizing Domain Names in Applications (IDNA)). Было определено четыре новых флага:- AI_IDN
- Если указан этот флаг, то, в случае необходимости, имя узла, указанного в node, будет преобразовано в IDN-формат. Исходной кодировкой будет текущая локаль.
- Если имя на входе содержит символы не-ASCII, то будет задействовано кодирование IDN. Части имени узла (разделенные точками), которые содержат символы не-ASCII, будут закодированы с помощью ASCII Compatible Encoding (ACE) прежде, чем будут переданы функциям преобразования имен
- AI_CANONIDN
- При указанном флаге AI_CANONNAME после успешного преобразования имени getaddrinfo() вернет каноничное имя узла согласно значению структуры addrinfo. Возвращаемое значение будет точной копией значения, возвращенного функцией разрешения имени.
- Если имя закодировано с помощью ACE, то оно будет содержать префикс xn-- для каждого из закодированных компонентов имени. Чтобы преобразовать эти компоненты в читаемый вид, вместе с флагом AI_CANONNAME следует передать AI_CANONIDN. Итоговая строка будет кодирована при помощи текущей локали.
- AI_IDN_ALLOW_UNASSIGNED, AI_IDN_USE_STD3_ASCII_RULES
- Установка этих флагов включает IDNA_ALLOW_UNASSIGNED (разрешать не назначенные кодовые точки Юникода) и IDNA_USE_STD3_ASCII_RULES (проверять вывод на соответствие имени узла STD3) соответственно для возможности работы с IDNA.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
В случае успеха getaddrinfo() возвращает 0, либо один из следующие ненулевых кодов ошибки:- EAI_ADDRFAMILY
- У указанного сетевого узла нет сетевых адресов в запрашиваемом семействе адресов.
- EAI_AGAIN
- Сервер имен вернул временную ошибку. Попробуйте позднее.
- EAI_BADFLAGS
- В hints.ai_flags содержатся неправильные флаги, либо hints.ai_flags содержит AI_CANONNAME, а name - NULL.
- EAI_FAIL
- Сервер имен вернул постоянную ошибку.
- EAI_FAMILY
- Запрашиваемое семейство адресов не поддерживается.
- EAI_MEMORY
- Не хватает памяти.
- EAI_NODATA
- Указанный сетевой узел существует, однако не имеет ни одного определенного сетевого адреса.
- EAI_NONAME
- node или service неизвестно; либо и node, и service равны NULL; либо в hints.ai_flags указан флаг AI_NUMERICSERV, а service не является числовой строкой порта.
- EAI_SERVICE
- Запрошенная служба не доступна для запрошенного типа сокета. Она может быть доступна через другой тип сокета. Например, эта ошибка может возникнуть, если в service указан «shell» (служба, доступная только для потоковых сокетов) при указанном в hints.ai_protocol IPPROTO_UDP, либо указанном в hints.ai_socktype SOCK_DGRAM. Также ошибка может возникнуть, если service не равно NULL, а в hints.ai_socktype указано значение SOCK_RAW (тип сокета, для которого концепция служб неприменима).
- EAI_SOCKTYPE
- Запрашиваемый тип сокетов не поддерживается. Такая ошибка может возникнуть, если hints.ai_socktype и hints.ai_protocol противоречат друг другу (например, SOCK_DGRAM и IPPROTO_TCP соответственно).
- EAI_SYSTEM
- Other system error; errno is set to indicate the error.
ФАЙЛЫ
/etc/gai.confАТРИБУТЫ
Описание терминов данного раздела смотрите в attributes(7).Интерфейс | Атрибут | Значение |
getaddrinfo() | Безвредность в нитях | MT-Safe env locale |
freeaddrinfo(), gai_strerror() | Безвредность в нитях | MT-Safe |
СТАНДАРТЫ
POSIX.1-2001, POSIX.1-2008. Функция getaddrinfo() описана в RFC 2553.ЗАМЕЧАНИЯ
getaddrinfo() поддерживает нотацию address% scope-id для указания IPv6 scope-ID. AI_ADDRCONFIG, AI_ALL и AI_V4MAPPED доступны, начиная с glibc 2.3.3. AI_NUMERICSERV доступен, начиная с glibc 2.3.4. According to POSIX.1, specifying hints as NULL should cause ai_flags to be assumed as 0. The GNU C library instead assumes a value of (AI_V4MAPPED | AI_ADDRCONFIG) for this case, since this value is considered an improvement on the specification.ПРИМЕРЫ
Следующие программы демонстрируют использование getaddrinfo(), gai_strerror(), freeaddrinfo() и getnameinfo(3). Это программы эхо-сервера и клиента UDP-дейтаграмм.Серверная программа
#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #define BUF_SIZE 500 int main(int argc, char *argv[]) { int sfd, s; char buf[BUF_SIZE]; ssize_t nread; socklen_t peer_addrlen; struct addrinfo hints; struct addrinfo *result, *rp; struct sockaddr_storage peer_addr; if (argc != 2) { fprintf(stderr, "Usage: %s port\n", argv[0]); exit(EXIT_FAILURE); } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; s = getaddrinfo(NULL, argv[1], &hints, &result); if (s != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); exit(EXIT_FAILURE); } /* getaddrinfo() возвращает список структур адресов. Идет проверка каждого адреса до успешного bind(2). Если socket(2) (или bind(2)) терпит неудачу, мы (закрываем сокет и) пробуем следующий. */ for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) break; /* Успех */ close(sfd); } freeaddrinfo(result); /* Больше не нужен */ if (rp == NULL) { /* Нет успешных адресов */ fprintf(stderr, "Could not bind\n"); exit(EXIT_FAILURE); } /* Read datagrams and echo them back to sender. */ for (;;) { char host[NI_MAXHOST], service[NI_MAXSERV]; peer_addrlen = sizeof(peer_addr); nread = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &peer_addr, &peer_addrlen); if (nread == -1) continue; /* Ignore failed request */ s = getnameinfo((struct sockaddr *) &peer_addr, peer_addrlen, host, NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICSERV); if (s == 0) printf("Received %zd bytes from %s:%s\n", nread, host, service); else fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s)); if (sendto(sfd, buf, nread, 0, (struct sockaddr *) &peer_addr, peer_addrlen) != nread) { fprintf(stderr, "Error sending response\n"); } } }
Клиентская программа
#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #define BUF_SIZE 500 int main(int argc, char *argv[]) { int sfd, s; char buf[BUF_SIZE]; size_t len; ssize_t nread; struct addrinfo hints; struct addrinfo *result, *rp; if (argc < 3) { fprintf(stderr, "Usage: %s host port msg...\n", argv[0]); exit(EXIT_FAILURE); } /* Obtain address(es) matching host/port. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ s = getaddrinfo(argv[1], argv[2], &hints, &result); if (s != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); exit(EXIT_FAILURE); } /* getaddrinfo() возвращает список структур адресов. Идет проверка каждого адреса до успешного connect(2). Если socket(2) (или connect(2)) терпит неудачу, мы (закрываем сокет и) пробуем следующий. */ for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Успех */ close(sfd); } freeaddrinfo(result); /* Больше не нужен */ if (rp == NULL) { /* Нет успешных адресов */ fprintf(stderr, "Could not connect\n"); exit(EXIT_FAILURE); } /* Send remaining command-line arguments as separate datagrams, and read responses from server. */ for (size_t j = 3; j < argc; j++) { len = strlen(argv[j]) + 1; /* +1 for terminating null byte */ if (len > BUF_SIZE) { fprintf(stderr, "Ignoring long message in argument %zu\n", j); continue; } if (write(sfd, argv[j], len) != len) { fprintf(stderr, "partial/failed write\n"); exit(EXIT_FAILURE); } nread = read(sfd, buf, BUF_SIZE); if (nread == -1) { perror("read"); exit(EXIT_FAILURE); } printf("Получено %zd байт: %s\n", nread, buf); } exit(EXIT_SUCCESS); }
СМ. ТАКЖЕ
getaddrinfo_a(3), gethostbyname(3), getnameinfo(3), inet(3), gai.conf(5), hostname(7), ip(7)ПЕРЕВОД
Русский перевод этой страницы руководства был сделан Azamat Hackimov <[email protected]>, Dmitry Bolkhovskikh <[email protected]>, Vladislav <[email protected]>, Yuri Kozlov <[email protected]> и Иван Павлов <[email protected]> Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ. Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на [email protected]5 февраля 2023 г. | Linux man-pages 6.03 |