Листинг 23.6. Функция sctp_strcli, отправляющая внеочередные данные
//sctp/sctp_strcli_un.c
18 out_sz = strlen(sendline);
19 Sctp_sendmsg(sock_fd, sendline, out_sz,
20 to, tolen, 0, MSG_UNORDERED, sri.sinfo_stream, 0, 0);
Отправка внеочередных данных
18-20
Функция sctp_str_cli
практически не отличается от той, которую мы разработали в разделе 10.4. Единственное изменение произошло в строке 21: клиент передает флаг MSG_UNORDERED
, включающий механизм частичной доставки. Обычно все сообщения внутри потока упорядочиваются по номерам. Флаг MSG_UNORDERED
позволяет отправить сообщение без порядкового номера. Такое сообщение доставляется адресату сразу после получения его стеком SCTP, даже если другие внеочередные сообщения, отправленные ранее по тому же потоку, еще не были приняты.
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
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 представлен модифицированный эхо-сервер, связывающий сокет с набором адресов, передаваемых в командной строке. Мы слегка изменили код сервера, чтобы он отправлял эхо-сообщения по тем потокам, по которым были приняты исходные сообщения.
Читать дальше
Конец ознакомительного отрывка
Купить книгу