UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
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_connect
Теперь мы напишем две функции, использующие функцию
getaddrinfo
tcp_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-13
getaddrinfo
AF_UNSPEC
SOCK_STREAM
14-25
socket
connect
socket
connect
break
freeaddrinfo
Эта функция (как и другие наши функции, предоставляющие более простой интерфейс для функции
getaddrinfo
getaddrinfo
connect
EAI_<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