Страница 131 из 399
10 hints.ai_socktype = socktype; /* 0, SOCK_STREAM, SOCK_DGRAM, ... */
11 if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
12 return (NULL);
13 return (res); /* возвращает указатель на первый элемент в связном
списке */
14 }
7-13 Функция инициализирует структуру рекомендаций (hints), вызывает функцию getaddrinfo и возвращает пустой указатель, если происходит ошибка.
Мы вызываем эту функцию в листинге 16.11, когда нам нужно использовать getaddrinfo для получения информации об узле и о службе и при этом мы хотим установить соединение самостоятельно.
11.12. Функция tcp_co
Теперь мы напишем две функции, использующие функцию getaddrinfo для обработки большинства сценариев клиентов и серверов TCP, которые мы создаем. Первая из этих функций, tcp_co
#include "unp.h"
int tcp_co
<i>Возвращает: в случае успешного соединения - дескриптор присоединенного сокета, в случае ошибки не возвращается ничего</i>
В листинге 11.4 показан исходный код.
Листинг 11.4. Функция tcp_co
//lib/tcp_co
1 #include "unp.h"
2 int
3 tcp_co
4 {
5 int sockfd, n;
6 struct addrinfo hints, *res, *ressave;
7 bzero(&hints, sizeof(struct addrinfo));
8 hints.ai_family = AF_UNSPEC;
9 hints.ai_socktype = SOCK_STREAM;
10 if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
11 err_quit("tcp_co
12 host, serv, gai_strerror(n));
13 ressave = res;
14 do {
15 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
16 if (sockfd < 0)
17 continue; /* игнорируем этот адрес */
18 if (co
19 break; /* успех */
20 Close(sockfd); /* игнорируем этот адрес */
21 } while ((res = res->ai_next) != NULL);
22 if (res == NULL) /* значение errno устанавливается при
последней попытке co
23 err_sys("tcp_co
24 freeaddrinfo(ressave);
25 return (sockfd);
26 }
7-13 функция getaddrinfo вызывается один раз, когда мы задаем семейство адресов AF_UNSPEC и тип сокета SOCK_STREAM.
14-25 Затем пробуется каждый IP-адрес: вызываются функции socket и co
Эта функция (как и другие наши функции, предоставляющие более простой интерфейс для функции getaddrinfo в следующих разделах) завершается, если либо оказывается неудачным вызов функции getaddrinfo, либо вызов функции co
Tcp_co
return(tcp_co
}
Тем не менее мы по-прежнему вызываем функцию-обертку вместо функции tcp_co
Проблема с возвращаемым значением заключается в том, что дескрипторы неотрицательные, но мы не знаем, положительны или отрицательны значения EAI_xxx. Если бы эти значения были положительными, мы могли бы возвратить равные им по абсолютной величине отрицательные значения, когда вызов функции getaddrinfo окажется неудачным. Но мы также должны возвратить некое другое отрицательное значение, чтобы указать, что все структуры были перепробованы безуспешно.
Пример: клиент времени и даты
В листинге 11.5 показан наш клиент времени и даты из листинга 1.1, переписанный с использованием функции tcp_co
Листинг 11.5. Клиент времени и даты, переписанный с использованием функции tcp_co