Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:

Аргументы функции те же, что и для функции

tcp_listen
: необязательный
hostname
, обязательный
service
(для связывания номер порта) и необязательный указатель на переменную, в которой возвращается размер структуры адреса сокета. В листинге 11.12 представлен исходный код.

Листинг 11.12. Функция udp_server: создание неприсоединенного сокета для сервера UDP

//lib/udp_server.c

1 #include "unp.h"

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)

15 sockfd = Udp_server(argv[1], argv[2], &addrlen);

16 else

17 err_quit("usage: daytimeudpsrv [ <host> ] <service or port>");

18 for (;;) {

19 len = sizeof(cliaddr);

20 n = Recvfrom(sockfd, buff, MAXLINE, 0, (SA*)&cliaddr, &len);

21 printf("datagram from %s\n", Sock_ntop((SA*)&cliaddr, len));

22 ticks = time(NULL);

23 snprintf(buff, sizeof(buff), "% 24s\r\n", ctime(&ticks));

24 Sendto(sockfd, buff, strlen(buff), 0, (SA*)&cliaddr, len);

25 }

26 }

11.17. Функция getnameinfo

Эта функция дополняет функцию

getaddrinfo
: она получает адрес сокета и возвращает одну символьную строку с описанием узла и другую символьную строку с описанием службы. Эта функция предоставляет указанную информацию в не зависящем от протокола виде, то есть вызывающему процессу неважно, какой тип адреса протокола содержится в структуре адреса сокета, поскольку эти подробности обрабатываются функцией.

Поделиться с друзьями: