Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
void ** saptr , socklen_t * lenp );
Возвращает: дескриптор неприсоединенного сокета в случае успешного выполнения, в случае ошибки не возвращает ничего
Эта функция создает неприсоединенный сокет UDP, возвращая три элемента. Во-первых, возвращаемое значение функции — это дескриптор сокета. Во-вторых, saptr
— это адрес указателя (объявляемого вызывающим процессом) на структуру адреса сокета (которая динамически размещается в памяти функцией udp_client
), и в этой структуре функция хранит IP-адрес получателя и номер порта для будущих вызовов функции sendto
. Размер этой структуры адреса сокета возвращается как значение переменной, на которую указывает lenp
. Последний аргумент не может быть пустым указателем (как это допустимо для последнего аргумента функции tcp_listen
), поскольку длина структуры адреса сокета требуется в любых вызовах функций sendto
и recvfrom
.
В листинге 11.9 показан исходный код для этой функции.
Листинг 11.9. Функция udp_client: создание неприсоединенного сокета UDP
//lib/udp_client.c
1 #include "unp.h"
2 int
3 udp_client(const char *host, const char *serv, void **saptr, socklen_t *lenp)
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_DGRAM;
10 if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
11 err_quit("udp_client 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 break; /* успех */
18 } while ((res = res->ai_next) != NULL);
19 if (res == NULL) /* значение errno устанавливается при последнем
вызове функции socket() */
20 err_sys("udp_client error for %s, %s", host, serv);
21 *saptr = Malloc(res->ai_addrlen);
22 memcpy(*saptr, res->ai_addr, res->ai_addrlen);
23 *lenp = res->ai_addrlen;
24 freeaddrinfo(ressave);
25 return (sockfd);
26 }
Функция getaddrinfo
преобразует аргументы hostname
и service
. Создается дейтаграммный сокет. Выделяется память для одной структуры адреса сокета, и структура адреса сокета, соответствующая созданному сокету, копируется в память.
Пример: не зависящий от протокола UDP-клиент времени и даты
Теперь мы перепишем наш клиент времени и даты, показанный в листинге 11.3, так, чтобы в нем использовалась наша функция udp_client
. В листинге 11.10 представлен не зависящий от протокола исходный код.
Листинг 11.10. UDP-клиент времени и даты, использующий нашу функцию udp_client
//names/daytimeudpcli1.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 salen;
8 struct sockaddr *sa;
9 if (argc != 3)
10 err_quit
11 ("usage; daytimeudpcli1 ");
12 sockfd = Udp_client(argv[1], argv[2], (void**)&sa, &salen);
13 printf("sending to %s\n", Sock_ntop_host(sa, salen));
14 Sendto(sockfd, "", 1, 0, sa, salen); /* посылается 1-байтовая
дейтаграмма */
15 n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
16 recvline[n] = 0; /* завершающий пустой байт */
17 Fputs(recvline, stdout);
18 exit(0);
19 }
12-17
Мы вызываем нашу функцию udp_client
и затем выводим IP-адрес и порт сервера, которому мы отправим нашу дейтаграмму UDP. Мы посылаем однобайтовую дейтаграмму и затем читаем и выводим ответ сервера.
Нам достаточно отправить дейтаграмму, содержащую 0 байт, поскольку ответ сервера времени и даты инициируется самим получением дейтаграммы от клиента, независимо от ее длины и содержания. Но многие реализации SVR4 не допускают нулевой длины дейтаграмм UDP.
Мы запускаем наш клиент, задавая имя узла с записью типа AAAA и типа А. Поскольку функция getaddrinfo
в первую очередь возвращает структуру с записью типа AAAA, создается сокет IPv6:
freebsd % daytimeudpcli1 aix daytime
sending to 3ffe:b80:1f8d:2:204:acff:fe17:bf38
Sun Jul 23:21:12 2003
Затем мы задаем адрес того же узла в точечно-десятичной записи, в результате чего создается сокет IPv4:
freebsd % daytimeudpcli1 192.168.42.2 daytime
sending to 192.168.42.2
Sun Jul 23:21:40 2003
11.15. Функция udp_connect
Наша функция udp_connect
создает присоединенный сокет UDP.
#include "unp.h"
int udp_connect(const char * hostname , const char * service );
Возвращает; дескриптор присоединенного сокета в случае успешного выполнения, в случае ошибки ничего не возвращает
В случае присоединенного сокета UDP два последних аргумента, которые требовались в функции udp_client
, больше не нужны. Вызывающий процесс может вызвать функцию write
вместо sendto
, таким образом нашей функции не нужно возвращать структуру адреса сокета и ее длину. В листинге 11.11 представлен исходный код.
Листинг 11.11. Функция udp_connect: создание присоединенного сокета UDP
//lib/udp_connect.c
1 #include "unp.h"
2 int
3 udp_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_DGRAM;
10 if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
11 err_quit("udp_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("udp_connect error for %s, %s", host, serv);
24 freeaddrinfo(ressave);
25 return (sockfd);
26 }
Эта функция почти идентична функции tcp_connect
. Однако отличие в том, что при вызове функции connect
для сокета UDP ничего не отправляется собеседнику. Если что-то не в порядке (собеседник недоступен или на заданном порте не запущен сервер), вызывающий процесс не обнаружит этого, пока не пошлет собеседнику дейтаграмму.
11.16. Функция udp_server
Наша последняя функция, предоставляющая более простой интерфейс для функции getaddrinfo
, — это функция udp_server
.
#include "unp.h"
int udp_server(const char * hostname , const char * service , socklen_t * lenptr );
Возвращает; дескриптор неприсоединенного сокета в случае успешного выполнения, в случае ошибки не возвращает ничего
Аргументы функции те же, что и для функции tcp_listen
: необязательный hostname
, обязательный service
(для связывания номер порта) и необязательный указатель на переменную, в которой возвращается размер структуры адреса сокета. В листинге 11.12 представлен исходный код.
Интервал:
Закладка: