Уильям Стивенс - 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. Получение анонсов сеансов многоадресной передачи
Интервал:
Закладка: