Добавить в цитаты Настройки чтения

Страница 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 &quot;unp.h&quot;

 2 int

 3 tcp_co

 4 {

 5  int sockfd, n;

 6  struct addrinfo hints, *res, *ressave;

 7  bzero(&amp;hints, sizeof(struct addrinfo));

 8  hints.ai_family = AF_UNSPEC;

 9  hints.ai_socktype = SOCK_STREAM;

10  if ((n = getaddrinfo(host, serv, &amp;hints, &amp;res)) != 0)

11   err_quit(&quot;tcp_co

12   host, serv, gai_strerror(n));

13  ressave = res;

14  do {

15   sockfd = socket(res-&gt;ai_family, res-&gt;ai_socktype, res-&gt;ai_protocol);

16   if (sockfd &lt; 0)

17    continue; /* игнорируем этот адрес */

18   if (co

19    break; /* успех */

20   Close(sockfd); /* игнорируем этот адрес */

21  } while ((res = res-&gt;ai_next) != NULL);

22  if (res == NULL) /* значение errno устанавливается при

                        последней попытке co

23   err_sys(&quot;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