Литмир - Электронная Библиотека
Содержание  
A
A

FreeBSD-lap:

Сервер отображает сообщения обо всех происходящих событиях (приеме входящего соединения, получении сообщения, завершении соединения).

FreeBSD-lap:<b>./sctpserv06</b>

SCTP_ADAPTION_INDICATION:0x504c5253

SCTP_ASSOC_CHANGE: COMMUNICATION UP, assoc=c99e2680h

SCTP_SHUTDOWN_EVENT; assoc=c99e2680h

SCTP_ASSOC_CHANGE: SHUTDOWN COMPLETE, assoc=c99e2680h

<b>Control-C</b>

Как видите, сервер действительно выводит сообщения обо всех происходящих событиях транспортного уровня.

23.5. Неупорядоченные данные

В обычном режиме SCTP обеспечивает надежную упорядоченную доставку данных. Кроме того, SCTP предоставляет и сервис надежной неупорядоченной доставки. Сообщение с флагом

MSG_UNORDERED
отправляется вне очереди и делается доступным для чтения сразу же после приема на удаленном узле. Такое сообщение может быть отправлено по любому потоку. Ему не присваивается порядковый номер внутри какого-либо потока. В листинге 23.6 представлены изменения кода клиента, позволяющие ему отправлять внеочередные запросы серверу.

Листинг 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 &quot;unp.h&quot;

 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, &quot;%d&quot;, SERV_PORT);

12  for (i=0; i&lt;argc; i++ ) {

13   addr = Host_serv(argv[i], portbuf, AF_UNSPEC, SOCK_SEQPACKET);

14   memcpy(p, addr-&gt;ai_addr, addr-&gt;ai_addrlen);

15   freeaddrinfo(addr);

16   addrcnt++;

17   p += addr-&gt;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
, в качестве аргументов которой используется раскодированный ранее набор адресов.

262
{"b":"225366","o":1}