25 if (ifi->ifi_flags & IFF_BROADCAST) {
26 /* пытаемся связать широковещательный адрес */
27 sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
28 Setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
29 sa = (struct sockaddr_in*)ifi->ifi_brdaddr;
30 sa->sin_family = AF_INET;
31 sa->sin_port = htons(SERV_PORT);
32 if (bind(sockfd, (SA*)sa, sizeof(*sa)) < 0) {
33 if (errno == EADDRINUSE) {
34 printf("EADDRINUSE: %s\n",
35 Sock_ntop((SA*)sa, sizeof(*sa)));
36 Close(sockfd);
37 continue;
38 } else
39 err_sys("bind error for %s",
40 Sock_ntop((SA*)sa, sizeof(*sa)));
41 }
42 printf("bound %s\n", Sock_ntop((SA*)sa, sizeof(*sa)));
43 if ((pid = Fork()) == 0) { /* дочерний процесс */
44 mydg_echo(sockfd, (SA*)&cliaddr, sizeof(cliaddr),
45 (SA*)sa);
46 exit(0); /* не выполняется */
47 }
48 }
49 }
25-42
Если интерфейс поддерживает широковещательную передачу, создается сокет UDP и с ним связывается широковещательный адрес. На этот раз мы позволим функции bind
завершиться с ошибкой EADDRINUSE
, поскольку если у интерфейса имеется несколько дополнительных адресов (псевдонимов) в одной подсети, то каждый из различных адресов направленной передачи будет иметь один и тот же широковещательный адрес. Подобный пример приведен после листинга 17.3. В этом сценарии мы предполагаем, что успешно выполнится только первая функция bind
.
43-47
Порождается дочерний процесс, и он вызывает функцию mydg_echo
.
Заключительная часть функции main
показана в листинге 22.15. В этом коде при помощи функции bind
происходит связывание с универсальным адресом для обработки любого адреса получателя, отличного от адресов направленной и широковещательной передачи, которые уже связаны. На этот сокет будут приходить только дейтаграммы, предназначенные для ограниченного широковещательного адреса (255.255.255.255).
Листинг 22.15. Заключительная часть сервера UDP, связывающегося со всеми адресами
//advio/udpserv03.c
50 /* связываем универсальный адрес */
51 sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
52 Setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
53 bzero(&wildaddr, sizeof(wildaddr));
54 wildaddr.sin_family = AF_INET;
55 wildaddr.sin_addr.s_addr = htonl(INADDR_ANY);
56 wildaddr.sin_port = htons(SERV_PORT);
57 Bind(sockfd, (SA*)&wildaddr, sizeof(wildaddr));
58 printf("bound %s\n", Sock_ntop((SA*)&wildaddr, sizeof(wildaddr)));
59 if ((pid = Fork()) == 0) { /* дочерний процесс */
60 mydg_echo(sockfd, (SA*)&cliaddr, sizeof(cliaddr), (SA*)sa);
61 exit(0); /* не выполняется */
62 }
63 exit(0);
64 }
50-62
Создается сокет UDP, устанавливается параметр сокета SO_REUSEADDR
и происходит связывание с универсальным IP-адресом. Порождается дочерний процесс, вызывающий функцию mydg_echo
.
63
Функция main
завершается, и сервер продолжает выполнять работу, как и все порожденные дочерние процессы.
Функция mydg_echo
, которая выполняется всеми дочерними процессами, показана в листинге 22.16.
Листинг 22.16. Функция mydg_echo
//advio/udpserv03.c
65 void
66 mydg_echo(int sockfd, SA *pcliaddr, socklen_t clilen, SA *myaddr)
67 {
68 int n;
69 char mesg[MAXLINE];