Литмир - Электронная Библиотека
Содержание  
A
A

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
: она получает адрес сокета и возвращает одну символьную строку с описанием узла и другую символьную строку с описанием службы. Эта функция предоставляет указанную информацию в не зависящем от протокола виде, то есть вызывающему процессу неважно, какой тип адреса протокола содержится в структуре адреса сокета, поскольку эти подробности обрабатываются функцией.

#include <netdb.h>

int getnameinfo(const struct sockaddr *<i>sockaddr</i>, socklen_t <i>addrlen</i>, char *<i>host</i>,

 size_t <i>hostlen</i>, char *<i>serv</i>, size_t <i>servlen</i>, int <i>flags</i>);

<i>Возвращает 0 в случае успешного выполнения, -1 в случае ошибки</i>

Аргумент

sockaddr
указывает на структуру адреса сокета, содержащую адрес протокола, преобразуемый в строку, удобную для человеческого восприятия, а аргумент
addrlen
содержит длину этой структуры. Эта структура и ее длина обычно возвращаются любой из следующих функций:
accept
,
recvfrom
,
getsockname
или
getpeername
.

Вызывающий процесс выделяет в памяти пространство для двух строк, удобных для человеческого восприятия: аргументы

host
и
hostlen
определяют строку, описывающую узел, а аргументы
serv
и
servlen
определяют строку, которая описывает службы. Если вызывающему процессу не нужна возвращаемая строка с описанием узла, задается нулевая длина этой строки (
hostlen
). Аналогично, нулевое значение аргумента
servlen
означает, что не нужно возвращать информацию о службе.

137
{"b":"225366","o":1}