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
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 представлен исходный код.