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
.
Завершение работы функции main
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];
70 socklen_t len;
71 for (;;) {
72 len = clilen;
73 n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
74 printf("child %d, datagram from %s", getpid(),
75 Sock_ntop(pcliaddr, len));
76 printf(", to %s\n", Sock_ntop(myaddr, clilen));
77 Sendto(sockfd, mesg, n, 0, pcliaddr, len);
78 }
79 }
Новый аргумент
65-66
Четвертым аргументом этой функции является IP-адрес, связанный с сокетом. Этот сокет должен получать только дейтаграммы, предназначенные для данного IP-адреса. Если IP-адрес является универсальным, сокет должен получать только те дейтаграммы, которые не подходят ни для какого другого сокета, связанного с тем же портом.
Чтение дейтаграммы и отражение ответа
71-78
Дейтаграмма читается с помощью функции recvfrom
и отправляется клиенту обратно с помощью функции sendto
. Эта функция также выводит IP-адрес клиента и IP-адрес, который был связан с сокетом.
Запустим эту программу на нашем узле solaris
после установки псевдонима для интерфейса hme0
Ethernet. Адрес псевдонима: узел 200 в сети 10.0.0/24.
solaris % udpserv03
bound 127.0.0.1:9877 интерфейс закольцовки
bound 10.0.0.200:9877 направленный адрес интерфейса hme0:1
bound 10.0.0.255:9877 широковещательный адрес интерфейса hme0:1
bound 192.168.1.20:9877 направленный адрес интерфейса hme0
bound 192.168.1.255:9877 широковещательный адрес интерфейса hme0
bound 0.0.0.0.9877 универсальный адрес
При помощи утилиты netstat
мы можем проверить, что все сокеты связаны с указанными IP-адресами и портом:
solaris % netstat -na | grep 9877
127.0.0.1.9877 Idle
10.0.0.200.9877 Idle
*.9877 Idle
192.129.100.100.9877 Idle
*.9877 Idle
*.9877 Idle
Читать дальше
Конец ознакомительного отрывка
Купить книгу