Троан Эрик В.
Шрифт:
#include <sys/types.h>
#include <socket.h>
#include <netdb.h>
void freeaddrinfo(struct addrinfo * res);
Единственным параметром для
freeaddrinfo
является указатель на первый узел в списке. Каждый узел в возвращаемом списке имеет тип
struct addrinfo
и специфицирует один адрес, соответствующий запросу. Каждый адрес содержит не только IPv4- или IPv6-адрес, он также определяет тип соединения (например, дейтаграмма) и протокол (такой как UDP). Если для одного IP-адреса в запросе подходит несколько типов соединений, то данный адрес включается в несколько узлов. Каждый узел содержит описанную ниже информацию.
•
ai_family
— семейство протоколов (PF_INET
или PF_INET6
), к которому принадлежит адрес. •
ai_socktype
— тип соединения для адреса (как правило, принимает одно из значений SOCK_STREAM
, SOCK_DGRAM
или SOCK_RAW
). •
ai_protocol
— протокол для адреса (обычно IPPROTO_TCP
или IPPROTO_UDP
). • Если в параметре
hints
был указан флаг AI_CANONNAME
, то ai_canonname
содержит каноническое имя для адреса. •
ai_addr
указывает на struct sockaddr
для соответствующего протокола. Например, если ai_family
принимает значение PF_INET
, то ai_addr
указывает на struct sockaddr_in
. Член ai_addrlen
определяет длину структуры, на которую указывает ai_addr
. • Если предусмотрен параметр
servicename
, то в качестве номера порта в каждом адресе устанавливается официальный порт данной службы. В противном случае номер порта для каждого адреса равен нулю. • Если не был передан параметр
hostname
, то номера портов устанавливаются для каждого адреса, однако в качестве IP-адреса определяется или адрес обратной связи, или неустановленный адрес (как указывалось ранее в описании флага AI_PASSIVE
). Все это может показаться достаточно запутанным. На самом деле, существует только два различных способа стандартного применения функции
getaddrinfo
. Большинство клиентских программ стремятся превратить имя хоста, передаваемое пользователем, и имя службы, известное программе, в полностью определенный адрес, с которым пользователь может установить соединение. Достичь этой цели нетрудно. Ниже приводится программа, которая принимает имя хоста как первый аргумент и имя службы как второй, после чего выполняет все необходимые преобразования. 1: /* clientlookup.c */
2:
3: #include <netdb.h>
4: #include <stdio.h>
5: #include <string.h>
6:
7: int main(int argc, const char ** argv) {
8: struct addrinfo hints, * addr;
9: const char * host = argv[1], * service = argv[2];
10: int rc;
11:
12: if (argc != 3) {
13: fprintf(stderr, "требуется в точности два аргумента\n");
14: return 1;
15: }
16:
17: memset(&hints, 0, sizeof(hints));
18:
19: hints.ai_socktype = SOCK_STREAM;
20: hints.ai_flags = AI_ADDRCONFIG;
21: if ((rc = getaddrinfo(host, service, &hints, &addr)))
22: fprintf(stderr, "сбой поиска\n");
23: else
24: freeaddrinfo(addr);
25:
26: return 0;
27: }
Давайте обратим внимание на строки 17–24 этой программы. После очистки структуры hints приложение запрашивает адреса
SOCK_STREAM
, которые используют протокол, сконфигурированный на локальной системе (путем установки флага AI_ADDRCONFIG
). Затем активизируется функция getaddrinfo
с именем хоста, именем службы, подсказками и в случае невозможности найти соответствие отображается сообщение об ошибке. Если все проходит нормально, то первый элемент в связном списке, на который указывает addr
, представляет собой соответствующий адрес, который программа может использовать для установки соединения с указанной службой и хостом. Программа не решает, через какой протокол (IPv4 или IPv6) соединение будет лучшим. Серверные приложения немного проще. В них, как правило, требуется согласиться на соединение с определенным портом, при этом на всех адресах. Если установлены флаги
AI_PASSIVE
, функция getaddrinfo
возвращает адрес, вынуждающий ядро разрешать все соединения (со всеми адресами, которые оно знает) при условии, что в качестве первого параметра передается NULL
. Как и в клиентском примере, используется AI_ADDRCONFIG
, дабы убедиться, что возвращаемый адрес соответствует протоколу, который поддерживает данная машина.