Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

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 }

Вызов функции getaddrinfo

7-13
функция
getaddrinfo
вызывается один раз, когда мы задаем семейство адресов
AF_UNSPEC
и тип сокета
SOCK_STREAM
.

Перебор всех структур addrinfo до успешного выполнения или до окончания списка

14-25
Затем пробуется каждый IP-адрес: вызываются функции
socket
и
connect
. Если выполнение функции
socket
неудачно, это не фатальная ошибка, так как такое может случиться, если был возвращен адрес IPv6, а ядро узла не поддерживает IPv6. Если выполнение функции
connect
успешно, выполняется функция
break
для выхода из цикла. В противном случае, после того как перепробованы все адреса, цикл также завершается. Функция
freeaddrinfo
освобождает всю динамически выделенную память.

Эта функция (как и другие наши функции, предоставляющие более простой интерфейс для функции

getaddrinfo
в следующих разделах) завершается, если либо оказывается неудачным вызов функции
getaddrinfo
, либо вызов функции
connect
не выполняется успешно. Возвращение из нашей функции возможно лишь в случае успешного выполнения. Было бы сложно возвратить код ошибки (одну из констант
EAI_ xxx
), не добавляя еще одного аргумента. Это значит, что наша функция-обертка тривиальна:

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

//names/daytimetcpcli.c

1 #include "unp.h"

2 int

3 main(int argc, char **argv)

4 {

5 int sockfd, n;

6 char recvline[MAXLINE + 1];

7 socklen_t len;

8 struct sockaddr_storage *ss;

9 if (argc != 3)

10 err_quit

11 ("usage, daytimetcpcli <hostname/IPaddress> <service/port#>");

12 sockfd = Tcp_connect(argv[1], argv[2]);

  • Читать дальше
  • 1
  • ...
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: