UNIX: разработка сетевых приложений, стр. 131
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-13hintsgetaddrinfoМы вызываем эту функцию в листинге 16.11, когда нам нужно использовать
getaddrinfo11.12. Функция tcp_connect
Теперь мы напишем две функции, использующие функцию
getaddrinfotcp_connect#include "unp.h"int tcp_connect(const char *<i>hostname</i>, const char *<i>service</i>);<i>Возвращает: в случае успешного соединения - дескриптор присоединенного сокета, в случае ошибки не возвращается ничего</i>В листинге 11.4 показан исходный код.
Листинг 11.4. Функция tcp_connect: выполнение обычных шагов клиента
/
/lib/tcp_connect.c 1 #include "unp.h" 2 int 3 tcp_connect(const char *host, const char *serv) 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_connect error for %s, %s: %s",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 (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)19 break; /* успех */20 Close(sockfd); /* игнорируем этот адрес */21 } while ((res = res->ai_next) != NULL);22 if (res == NULL) /* значение errno устанавливается при последней попытке connect() */23 err_sys("tcp_connect error for %s, %s", host, serv);24 freeaddrinfo(ressave);25 return (sockfd);26 }7-13getaddrinfoAF_UNSPECSOCK_STREAM14-25socketconnectsocketconnectbreakfreeaddrinfoЭта функция (как и другие наши функции, предоставляющие более простой интерфейс для функции
getaddrinfogetaddrinfoconnectEAI_<i>xxx</i>Tcp_connect(const char *host, const char *serv) { return(tcp_connect(host, serv));}Тем не менее мы по-прежнему вызываем функцию-обертку вместо функции
tcp_connectПроблема с возвращаемым значением заключается в том, что дескрипторы неотрицательные, но мы не знаем, положительны или отрицательны значения EAI_xxx. Если бы эти значения были положительными, мы могли бы возвратить равные им по абсолютной величине отрицательные значения, когда вызов функции getaddrinfo окажется неудачным. Но мы также должны возвратить некое другое отрицательное значение, чтобы указать, что все структуры были перепробованы безуспешно.
Пример: клиент времени и даты
В листинге 11.5 показан наш клиент времени и даты из листинга 1.1, переписанный с использованием функции
tcp_connectЛистинг 11.5. Клиент времени и даты, переписанный с использованием функции tcp_connect