Получить информацию об адресе сокета
#include <sys/socket.h>#include <netdb.h>int getaddrinfo( const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res );
NULL
может быть либо именем узла либо строкой, содержащей числовой адрес хоста (т.е. разделенный точками IPv4 адрес или шестнадцатеричный IPv6 адрес.)NULL
может быть либо именем сервера либо десятичным номером порта.libsocket
Функция getaddrinfo() представляет собой комбинацию gethostbyname() и getservbyname(), но в более усложненном исполнении.
Аргументы nodename и servname могут быть либо указателями на нуль-терминированные строки либо NULL
. Один или оба этих аргумента должны быть не NULL
. Обычно, со стороны клиента предоставляются и nodename и servname.
В случае успешного завершения, функция getaddrinfo() сохраняет в области памяти res указатель на связанный список из одной или нескольких struct addrinfo. Можно обрабатывать каждую struct addrinfo в списке при помощи указателя ai_next до достижения NULL
указателя. Каждая struct addrinfo содержит соответствующие аргументы ai_family, ai_socktype, и ai_protocol для вызова функции socket(). Аргумент ai_addr в struct addrinfo указывает на заполненную структуру адреса сокета, размер которой указан в ai_addrlen.
На случай, если сервер имен не отвечает, предусмотрен таймаут для каждого сервера имен, составляющий 1,5 минуты. |
Использование аргумента hints
Опционально, можно передать struct addrinfo, на которую указывает аргумент hints, предоставляющую вспомогательную информацию по типу сокета, который поддерживает пользовательское приложение.
В данной структуре, все поля, кроме ai_flags, ai_family, ai_socktype, и ai_protocol — должны быть нулями либо NULL
указателями. struct addrinfo из аргумента hints может обрабатывать несколько типов сокетов:
Обработать: | Установить: | В: |
---|---|---|
Любое семейство протоколов | ai_family | PF_UNSPEC |
Любой тип сокета | ai_socktype | 0 |
Любой протокол | ai_protocol | 0 |
Все вышеуказанное (в т.ч. установка ai_flags в 0 ) | hints | NULL |
Аргумент hints по умолчанию принимает все возможные варианты, но также воможно использовать его для ограниченного выбора:
SOCK_STREAM
. PF_INET
. Использование аргумента ai_flags в структуре hints
Можно установить аргумент ai_flags для последующей настройки структуры hints. Настройки для ai_flags включают в себя:
NULL
указатель, то часть IP адреса из структуры адреса сокета ai_addr устанавливается в INADDR_ANY
для IPv4 адреса или IN6ADDR_ANY_INIT
для IPv6 адреса. Если не устанавливать флаг AI_PASSIVE
, то возможно использование возвращеннной struct addrinfo для вызовов: NULL
указателем, то часть IP адреса из структуры адреса сокета ai_addr устанавливается значением адреса обратной связи. EAI_NONAME
. Возможные проблемы
Аргументы getaddrinfo() должны быть последовательны и однозначны, иначе данная функция вернет ошибку. Вот некоторые проблемы, с которыми можно столкнуться:
SOCK_STREAM
для ai_socktype, и в то же время указывающих IPPROTO_UDP
для ai_protocol.
SOCK_DGRAM
) на SOCK_STREAM
.
SOCK_RAW
для ai_socktype. (Имена служб не определены для пространства SOCK_RAW
в Интернете).
Функция getaddrinfo() динамически выделяет память для следующей информации:
Используйте freeaddrinfo() чтобы освободить память, выделенную под структуры addrinfo, и gai_strerror() чтобы расшифровать коды ошибок. |
Чтобы получить развернутое описание кода ошибки, используйте gai_strerror().
Следующий код пытается подключиться к сервису HTTP «www.kame.net» с помощью потокового сокета. Он перебирает все доступные адреса независимо от их семейства. Если узел назначения разрешается как адрес IPv4, то он использует сокет AF_INET
. Точно так же он использует сокет AF_INET6
, если он разрешается как IPv6. Обратите внимание, что здесь нет жестко запрограммированных ссылок на какое-либо конкретное семейство адресов; код работает, даже если getaddrinfo() возвращает адреса, не являющиеся IPv4/v6.
struct addrinfo hints, *res, *res0;int error, s;const char *cause = NULL;memset( &hints, 0, sizeof( hints ) );hints.ai_family = PF_UNSPEC;hints.ai_socktype = SOCK_STREAM;error = getaddrinfo( "www.kame.net", "http", &hints, &res0 );if ( error ){err1( 1, "%s", gai_strerror( error ) );/*NOTREACHED*/}s = -1;for ( res = res0; res; res = res->ai_next ){s = socket( res->ai_family, res->ai_socktype, res->ai_protocol );if ( s < 0 ){cause = "socket";continue;}if ( connect( s, res->ai_addr, res->ai_addrlen ) < 0 ){cause = "connect";close( s );s = -1;continue;}break; /* okay we got one */}if ( s < 0 ){err( 1, cause );/*NOTREACHED*/}freeaddrinfo( res0 );
В следующем примере предпринимается попытка открыть сокет, ожидающий специальный символ, в службе HTTP для всех доступных семейств адресов:
struct addrinfo hints, *res, *res0;int error, s[MAXSOCK], nsock;const char *cause = NULL;memset( &hints, 0, sizeof( hints ) );hints.ai_family = PF_UNSPEC;hints.ai_socktype = SOCK_STREAM;hints.ai_flags = AI_PASSIVE;error = getaddrinfo( NULL, "http", &hints, &res0 );if ( error ){err1( 1, "%s", gai_strerror( error ) );/*NOTREACHED*/}nsock = 0;for ( res = res0; res && nsock < MAXSOCK; res = res->ai_next ){s[nsock] = socket( res->ai_family, res->ai_socktype, res->ai_protocol );if ( s[nsock] < 0 ){cause = "socket";continue;}if ( connect( s[nsock], res->ai_addr, res->ai_addrlen ) < 0 ){cause = "connect";close( s[nsock] );continue;}nsock++;}if ( nsock == 0 ){err( 1, cause );/*NOTREACHED*/}freeaddrinfo( res0 );
POSIX 1003.1
struct addrinfo, freeaddrinfo(), gai_strerror()
/etc/nsswitch.conf в Справочнике по Утилитам
Предыдущий раздел: Описание API сетевой библиотеки