Шрифт:
2 int
3 udp_server(const char *host, const char *serv, socklen_t *addrlenp)
4 {
5 int sockfd, n;
6 struct addrinfo hints, *res, *ressave;
7 bzero(&hints, sizeof(struct addrinfo));
8 hints.ai_flags = AI_PASSIVE;
9 hints.ai_family = AF_UNSPEC;
10 hints.ai_socktype = SOCK_DGRAM;
11 if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
12 err_quit("udp_server error for %s, %s: %s",
13 host, serv, gai_strerror(n));
14 ressave = res;
15 do {
16 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
17 if (sockfd < 0)
18 continue; /* ошибка, пробуем следующий адрес */
19 if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0)
20 break; /* успех */
21 Close(sockfd); /* ошибка при вызове функции bind, закрываем
сокет и пробуем следующий адрес */
22 } while ((res = res->ai_next) != NULL);
23 if (res == NULL) /* значение errno устанавливается при
последнем вызове функции socket or bind */
24 err_sys("udp_server error for %s, %s", host, serv);
25 if (addrlenp)
26 *addrlenp = res->ai_addrlen; /* возвращается размер адреса
протокола */
27 freeaddrinfo(ressave);
28 return (sockfd);
29 }
Эта функция практически идентична функции
tcp_listen
, в ней нет только вызова функции listen
. Мы устанавливаем семейство адресов AF_UNSPEC
, но вызывающий процесс может использовать ту же технологию, которую мы описали при рассмотрении листинга 11.6, чтобы потребовать использование определенного протокола (IPv4 или IPv6). Мы не устанавливаем параметр сокета
SO_REUSEADDR
для сокета UDP, поскольку этот параметр сокета может допустить связывание множества сокетов с одним и тем же портом UDP на узлах, поддерживающих многоадресную передачу, как мы говорили в разделе 7.5. Поскольку у сокета UDP нет аналога состояния TIME_WAIT, свойственного сокетам TCP, нет необходимости устанавливать этот параметр при запуске сервера. Пример: не зависящий от протокола UDP-сервер времени и даты
В листинге 11.13 представлен наш сервер времени и даты, полученный путем модификации листинга 11.8 и предназначенный для использования UDP.
Листинг 11.13. Не зависящий от протокола UDP-сервер времени и даты
//names/daytimeudpsrv2.c
1 #include "unp.h"
2 #include <time.h>
3 int
4 main(int argc, char **argv)
5 {
6 int sockfd;
7 ssize_t n;
8 char buff[MAXLINE];
9 time_t ticks;
10 socklen_t addrlen, len;
11 struct sockaddr_storage cliaddr;
12 if (argc == 2)
13 sockfd = Udp_server(NULL, argv[1], &addrlen);
14 else if (argc == 3)