Книга: UNIX: разработка сетевых приложений
23.6. Связывание с подмножеством адресов
Разделы на этой странице:
23.6. Связывание с подмножеством адресов
Некоторым приложениям требуется связывать один сокет с некоторым конкретным подмножеством всех адресов узла. Протоколы TCP и UDP не позволяют выделить подмножество адресов. Системный вызов bind
позволяет приложению связать сокет с единственным адресом или сразу со всеми адресами узла (то есть с универсальным адресом). Поэтому в SCTP был добавлен новый системный вызов sctp_bindx
, который позволяет приложению связываться с произвольным количеством адресов. Все адреса должны иметь один и тот же номер порта, а если ранее вызывалась функция bind
, то номер порта должен быть таким, как в вызове bind
. Если указать не тот порт, вызов sctp_bindx
завершится с ошибкой. В листинге 23.7 представлена функция, которую мы добавим к нашему серверу, чтобы получить возможность связывать сокет с адресами, передаваемыми в качестве аргументов командной строки.
Листинг 23.7. Функция, связывающая сокет с набором адресов
1 #include "unp.h"
2 int
3 sctp_bind_arg_list(int sock_fd, char **argv, int argc)
4 {
5 struct addrinfo *addr;
6 char *bindbuf, *p, portbuf[10];
7 int addrcnt=0;
8 int i;
9 bindbuf = (char*)Calloc(argc, sizeof(struct sockaddr_storage));
10 p = bindbuf;
11 sprintf(portbuf, "%d", SERV_PORT);
12 for (i=0; i<argc; i++ ) {
13 addr = Host_serv(argv[i], portbuf, AF_UNSPEC, SOCK_SEQPACKET);
14 memcpy(p, addr->ai_addr, addr->ai_addrlen);
15 freeaddrinfo(addr);
16 addrcnt++;
17 p += addr->ai_addrlen;
18 }
19 Sctp_bindx(sock_fd, (SA*)bindbuf, addrent, SCTP_BINDX_ADD_ADDR);
20 free(bindbuf);
21 return(0);
22 }
Выделение памяти под аргументы bind
9-10
Наша новая функция начинает работу с выделения памяти под аргументы функции sctp_bindx
. Обратите внимание, что функция sctp_bindx
может принимать в качестве аргументов адреса IPv4 и IPv6 в произвольных комбинациях. Для каждого адреса мы выделяем место под структуру sockaddr_storage
несмотря на то, что соответствующий аргумент sctp_bindx
представляет собой упакованный список адресов (см. рис. 9.3). В результате мы расходуем зря некоторый объем памяти, но зато функция работает быстрее, потому что ей не приходится вычислять точный объем памяти и лишний раз обрабатывать список аргументов.
Обработка аргументов
11-18
Мы подготавливаем portbuf
к хранению номера порта в ASCII-представлении, имея в виду вызов нашей обертки для getaddrinfo
, которая называется host_serv
. Каждый адрес с номером порта мы передаем host_serv
, указывая константы AF_UNSPEC
(протоколы IPv4 и IPv6) и SOCK_SEQPACKET
(протокол SCTP). Мы копируем первую возвращаемую структуру sockaddr
, игнорируя все остальные. Поскольку аргументами этой функции должны быть адреса в строковом представлении, а не имена, с каждым из которых может быть связано несколько адресов, это не вызывает проблем. Мы освобождаем буфер, увеличиваем количество адресов на единицу и перемещаем указатель на следующий элемент в упакованном массиве структур sockaddr
.
Вызов связывающей функции
19
Указатель устанавливается на начало буфера адресов, после чего вызывается функция sctp_bindx
, в качестве аргументов которой используется раскодированный ранее набор адресов.
Успешное завершение
20-21
Если мы добрались до этого места, можно считать, что выполнение прошло успешно, поэтому мы освобождаем память и возвращаем управление вызвавшему процессу.
В листинге 23.8 представлен модифицированный эхо-сервер, связывающий сокет с набором адресов, передаваемых в командной строке. Мы слегка изменили код сервера, чтобы он отправлял эхо-сообщения по тем потокам, по которым были приняты исходные сообщения.
Листинг 23.8. Сервер, работающий с произвольным набором адресов
if (argc < 2)
err_quit("Error, use %s [list of addresses to bind]n", argv[0]);
sock_fd = Socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP);
if (sctp_bind_arg_list(sock_fd, argv + 1, argc — 1))
err_sys("Can't bind the address set");
bzero(&evnts, sizeof(evnts));
evnts sctp_data_io_event = 1;
Работа с IPv6
14
Это тот же сервер, с которым мы работали во всех предыдущих разделах этой главы, но с незначительным изменением. Сервер создает сокет AF_INET6
, что позволяет ему работать с протоколом IP обеих версий.
Вызов sctp_bind_arg_list
15-16
Сервер вызывает новую функцию sctp_bind_arg_list
и передает ей список аргументов для обработки.
- 23.1. Введение
- 23.2. Сервер типа «один-ко-многим» с автоматическим закрытием
- 23.3. Частичная доставка
- 23.4. Уведомления
- 23.5. Неупорядоченные данные
- 23.6. Связывание с подмножеством адресов
- 23.7. Получение адресов
- 23.8. Определение идентификатора ассоциации по IP-адресу
- 23.9. Проверка соединения и ошибки доступа
- 23.10. Выделение ассоциации
- 23.11. Управление таймерами
- 23.12. Когда SCTP оказывается предпочтительнее TCP
- 23.13. Резюме
- Упражнения
- Фильтрация адресов
- Фильтрация нежелательных адресов
- Фильтрация неверных адресов
- Почему наша книга адресована прежде всего женщинам?
- Функции munmap() и do_munmap(): удаление интервала адресов
- Трансляция адресов
- 9.7. Преобразование обычных адресов в данные широты и долготы
- Глава 5 Распределение IP-адресов с помощью DHCP
- Использование статических IP-адресов
- Динамическое распределение IP-адресов
- Определение диапазона адресов
- Выделение фиксированных адресов