UNIX: разработка сетевых приложений
Часть 237 из 399 Информация о книге
22 exit(0);23 }Заранее известные имя и портАдрес многоадресной передачи, заданный для анонсов SAP — 224.2.127.254, а его имя —2-3. Все заранее известные адреса многоадресной передачи (см.sap.mcast.net) появляются в DNS в иерархииhttp://www.iana.org/assignments/multicast-addresses. Заранее известный порт UDP — это порт 9875.mcast.netСоздание сокета UDPМы вызываем нашу функцию12-17, чтобы просмотреть имя и порт, и она заполняет соответствующую структуру адреса сокета. Если не заданы аргументы командной строки, мы используем значения по умолчанию. В противном случае мы получаем адрес многоадресной передачи, порт и имя интерфейса из аргументов командной строки.udp_clientСвязывание порта с помощью функции bindМы устанавливаем параметр сокета18-19, чтобы позволить множеству экземпляров этой программы запуститься на узле, и с помощью функции bind связываем порт с сокетом. Связывая адрес многоадресной передачи с сокетом, мы запрещаем сокету получать какие-либо другие дейтаграммы UDP, которые могут быть получены для этого порта. Связывание этого адреса многоадресной передачи не является обязательным, но оно обеспечивает возможность фильтрации, благодаря чему ядро может не принимать пакеты, которые его не интересуют.SO_REUSEADDRПрисоединение к группеМы вызываем нашу функцию20, чтобы присоединиться к группе. Если имя интерфейса было задано в качестве аргумента командной строки, оно передается нашей функции, иначе мы позволяем ядру выбрать интерфейс, на котором будет происходить присоединение к группе.mcast_joinМы вызываем нашу функцию21, показанную в листинге 21.6, чтобы прочитать и вывести все анонсы.loopЛистинг 21.6. Цикл, получающий и выводящий анонсы SAP/SDP
//mysdr/loop.c1 #include "mysdr.h"2 void3 loop(int sockfd, socklen_t salen)4 {5 socklen_t len;6 ssize_t n;7 char *p;8 struct sockaddr *sa;9 struct sap_packet {10 uint32_t sap_header;11 uint32_t sap_src;12 char sap_data[BUFFSIZE];13 } buf;14 sa = Malloc(salen);15 for (;;) {15 len = salen;17 n = Recvfrom(sockfd, &buf, sizeof(buf) - 1, 0, sa, &len);18 ((char *)&buf)[n] = 0; /* завершающий нуль */19 buf.sap_header = ntohl(buf.sap_header);20 printf("From %s hash 0х%0х\n" Sock_ntop(sa, len),21 buf.sap_header & SAP_HASH_MASK);22 if (((buf.sap_header & SAP_VERSION_MASK) >> SAP_VERSION_SHIFT) > 1) {23 err_msg("... version field not 1 (0x%08x)", buf.sap_header);24 continue;25 }26 if (buf.sap_header & SAP_IPV6) {27 err_msg("... IPv6");28 continue;29 }30 if (buf.sap_header & (SAP_DELETE|SAP_ENCRYPTED|SAP_COMPRESSED)) {31 err_msg("... can't parse this packet type (0x%80x)",32 buf.sap_header);33 continue;34 }35 p = buf.sap_data + ((buf.sap_header & SAP AUTHLEN_MASK)36 >> SAP_AUTHLEN_SHIFT);37 if (strcmp(p.,"application/sdp") == 0)38 p += 16;39 printf(%s\n", p);40 }41 }Формат пакетаСтруктура9-13описывает пакет SDP: 32-разрядный заголовок SAP, за которым следует 32-разрядный адрес отправителя и сам анонс. Анонс представляет собой строки текста в стандарте ISO 8859-1 и не может превышать 1024 байта. В каждой дейтаграмме UDP допускается только один анонс сеанса.sap_packetЧтение дейтаграммы UDP, вывод параметров отправителя и содержимогоФункция15-21ждет следующую дейтаграмму UDP, предназначенную нашему сокету. Когда она приходит, мы помещаем в конец буфера пустой байт, исправляем порядок байтов заголовка и выводим адрес отправителя пакета и хэш SAP.recvfromПроверка заголовка SAPМы проверяем заголовок SAP, чтобы убедиться, что он относится к одному из тех типов, с которыми мы умеем работать. Пакеты SAP с адресами IPv6 в заголовках, а также сжатые и зашифрованные пакеты мы не обрабатываем.22-34Поиск начала и вывод анонсаМы пропускаем аутентифицирующие данные и тип пакета, после чего выводим содержимое оставшейся части.35-39В листинге 21.7 показано несколько типичных примеров результата выполнения нашей программы.
Листинг 21.7. Типичный анонс SAP/SDP
freebsd % <b>mysdr</b>From 128.223.83.33:1028 hash 0x0000 v=0o=- 60345 0 IN IP4 128.223.214.198s=UO Broadcast - NASA Videos - 25 Years of Progressi=25 Years of Progress, parts 1-13. Broadcast with Cisco System'sIP/TV using MPEG1 codec (6 hours 5 Minutes; repeats) More information