Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
18-22 Адрес сокета копируется непосредственно в поле группы. Вспомните, что поле это имеет тип sockaddr_storage, а потому достаточно велико для хранения адреса любого типа, поддерживаемого системой. Для предотвращения переполнения буфера (при ошибках в программе) мы проверяем размер sockaddrи возвращаем EINVAL, если он слишком велик.
23-24 Присоединение к группе выполняется вызовом setsockopt. Аргумент levelопределяется на основании семейства группового адреса вызовом нашей собственной функции family_to_level. Некоторые системы допускают несоответствие аргумента level семейству адреса сокета, например использование IPPROTO_IPс MCAST_JOIN_GROUP, даже если сокет относится к семейству AF_INET6, но это верно не для всех систем, поэтому мы и должны выполнить преобразование семейства к нужному значению level. Листинг этой тривиальной функции в книге мы не приводим, но исходный код этой функции вы можете скачать вместе со всеми остальными программами.
В листинге 21.2 представлена вторая часть функции mcast_join, обрабатывающая сокеты IPv4.
Листинг 21.2. Присоединение к группе: обработка сокета IPv4
26 switch (grp->sa_family) {
27 case AF_INET: {
28 struct ip_mreq mreq;
29 struct ifreq ifreq;
30 memcpy(&mreq.imr_multiaddr,
31 &((const struct sockaddr_in*)grp)->sin_addr,
32 sizeof(struct in_addr));
33 if (ifindex > 0) {
34 if (if_indextoname(ifindex, ifreq.ifr_name) == NULL) {
35 errno = ENXIO; /* i/f index not found */
36 return(-1);
37 }
38 goto doioctl;
39 } else if (ifname != NULL) {
40 strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
41 doioctl:
42 if (ioctl(sockfd, SIOCGIFADDR, &ifreq)
43 return(-1);
44 memcpy(&mreq.imr_interface,
45 &((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr,
46 sizeof(struct in_addr));
47 } else
48 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
49 return(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
50 &mreq, sizeof(mreq)));
51 }
33-38 Адрес многоадресной передачи IPv4 в структуре адреса сокета копируется в структуру ip_mreq. Если индекс был задан, вызывается функция if_indextoname, сохраняющая имя в нашей структуре ip_mreq. Если это выполняется успешно, мы переходим на точку вызова ioctl.
39-46 Имя вызывающего процесса копируется в структуру ip_mreq, а вызов SIOCGIFADDRфункции ioctlвозвращает адрес многоадресной передачи, связанный с этим именем. При успешном выполнении адрес IPv4 копируется в элемент imr_interfaceструктуры ip_mreq.
47-48 Если ни индекс, ни имя не заданы, используется универсальный адрес, что указывает ядру на необходимость выбрать интерфейс.
49-50 Функция setsockoptвыполняет присоединение к группе.
Третья, и последняя, часть функции, обрабатывающая сокеты IPv6, приведена в листинге 21.3.
Листинг 21.3. Присоединение к группе: обработка сокета IPv6
52 #ifdef IPV6
53 case AF_INET6: {
54 struct ipv6_mreq mreq6;
55 memcpy(&mreq6.ipv6mr_multiaddr,
56 &((const struct sockaddr_in6*) grp)->sin6_addr,
57 sizeof(struct in6_addr));
58 if (ifindex > 0) {
59 mreq6.ipv6mr_interface = ifindex;
60 } else if (ifname != NULL) {
61 if ((mreq6.ipv6mr_interface = if_nametoindex(ifname)) == 0) {
62 errno = ENXIO; /* интерфейс не найден */
63 return(-1);
64 }
65 } else
66 mreq6.ipv6mr_interface = 0;
67 return(setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
68 &mreq6, sizeof(mreq6)));
69 }
70 #endif
71 default:
72 errno = EAFNOSUPPORT;
73 return(-1);
74 }
75 #endif
76 }
55-57 Сначала адрес IPv6 копируется из структуры адреса сокета в структуру ipv6_mreq.
58-66 Если был задан индекс, он записывается в элемент ipv6mr_interface. Если индекс не задан, но задано имя, то для получения индекса вызывается функция if_nametoindex. В противном случае для функции setsockoptиндекс устанавливается в 0, что указывает ядру на необходимость выбрать интерфейс.
67-68 Выполняется присоединение к группе.
Пример: функция mcast_set_loop
В листинге 21.4 показана наша функция mcast_set_loop.
Поскольку аргументом является дескриптор сокета, а не структура адреса сокета, мы вызываем нашу функцию sockfd_to_family, чтобы получить семейство адресов сокета. Устанавливается соответствующий параметр сокета.
Мы не показываем исходный код для всех остальных функций mcast_ XXX , так как он свободно доступен в Интернете (см. предисловие).
Листинг 21.4. Установка параметра закольцовки для многоадресной передачи
//lib/mcast_set_loop.c
1 #include "unp.h"
2 int
3 mcast_set_loop(int sockfd, int onoff)
4 {
5 switch (sockfd_to_family(sockfd)) {
6 case AF_INET:{
7 u_char flag;
8 flag = onoff;
9 return (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
10 &flag, sizeof(flag)));
11 }
12 #ifdef IPV6
13 case AF_INET6:{
14 u_int flag;
15 flag = onoff;
16 return (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
17 &flag, sizeof(flag)));
18 }
19 #endif
20 default:
21 errno = EPROTONOSUPPORT;
22 return (-1);
23 }
24 }
21.8 Функция dg_cli, использующая многоадресную передачу
Мы изменяем нашу функцию dg_cli, показанную в листинге 20.1, просто удаляя вызов функции setsockopt. Как мы сказали ранее, для отправки дейтаграмм многоадресной передачи не нужно устанавливать ни одного параметра сокета многоадресной передачи, если нас устраивают заданные по умолчанию настройки интерфейса исходящих пакетов, значения TTL и параметра закольцовки. Мы запускаем нашу программу, задавая в качестве адреса получателя группу всех узлов (all-hosts group):
macosx % udpcli01 224.0.1.1
hi there
from 172.24.37.78: hi there MacOS X
from 172.24.37.94: hi there FreeBSD
Отвечают оба узла, находящиеся в подсети. На обоих работают многоадресные эхо-серверы. Каждый ответ является направленным, поскольку адрес отправителя запроса, используемый сервером в качестве адреса получателя ответа, является адресом направленной передачи.
Фрагментация IP и многоадресная передача
В конце раздела 20.4 мы отмечали, что в большинстве систем фрагментация широковещательной дейтаграммы не допускается по стратегическим соображениям. Фрагментация допускается при многоадресной передаче, что мы можем легко проверить, используя тот же файл с 2000-байтовой строкой:
macosx % udpcli01 224.0.1.1
from 172.24.37.78: xxxxxxx[...]
from 172.24.37.94: xxxxxxx[...]
21.9. Получение анонсов сеансов многоадресной передачи
Интервал:
Закладка: