UNIX: разработка сетевых приложений
FreeBSD-lap:Сервер отображает сообщения обо всех происходящих событиях (приеме входящего соединения, получении сообщения, завершении соединения).
FreeBSD-lap:<b>./sctpserv06</b>SCTP_ADAPTION_INDICATION:0x504c5253SCTP_ASSOC_CHANGE: COMMUNICATION UP, assoc=c99e2680hSCTP_SHUTDOWN_EVENT; assoc=c99e2680hSCTP_ASSOC_CHANGE: SHUTDOWN COMPLETE, assoc=c99e2680h<b>Control-C</b>Как видите, сервер действительно выводит сообщения обо всех происходящих событиях транспортного уровня.
23.5. Неупорядоченные данные
В обычном режиме SCTP обеспечивает надежную упорядоченную доставку данных. Кроме того, SCTP предоставляет и сервис надежной неупорядоченной доставки. Сообщение с флагом
отправляется вне очереди и делается доступным для чтения сразу же после приема на удаленном узле. Такое сообщение может быть отправлено по любому потоку. Ему не присваивается порядковый номер внутри какого-либо потока. В листинге 23.6 представлены изменения кода клиента, позволяющие ему отправлять внеочередные запросы серверу.MSG_UNORDEREDЛистинг 23.6. Функция sctp_strcli, отправляющая внеочередные данные
//sctp/sctp_strcli_un.c18 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практически не отличается от той, которую мы разработали в разделе 10.4. Единственное изменение произошло в строке 21: клиент передает флагsctp_str_cli, включающий механизм частичной доставки. Обычно все сообщения внутри потока упорядочиваются по номерам. ФлагMSG_UNORDEREDпозволяет отправить сообщение без порядкового номера. Такое сообщение доставляется адресату сразу после получения его стеком SCTP, даже если другие внеочередные сообщения, отправленные ранее по тому же потоку, еще не были приняты.MSG_UNORDERED23.6. Связывание с подмножеством адресов
Некоторым приложениям требуется связывать один сокет с некоторым конкретным подмножеством всех адресов узла. Протоколы TCP и UDP не позволяют выделить подмножество адресов. Системный вызов
позволяет приложению связать сокет с единственным адресом или сразу со всеми адресами узла (то есть с универсальным адресом). Поэтому в SCTP был добавлен новый системный вызовbind, который позволяет приложению связываться с произвольным количеством адресов. Все адреса должны иметь один и тот же номер порта, а если ранее вызывалась функцияsctp_bindx, то номер порта должен быть таким, как в вызовеbind. Если указать не тот порт, вызовbindзавершится с ошибкой. В листинге 23.7 представлена функция, которую мы добавим к нашему серверу, чтобы получить возможность связывать сокет с адресами, передаваемыми в качестве аргументов командной строки.sctp_bindxЛистинг 23.7. Функция, связывающая сокет с набором адресов
1 #include "unp.h"2 int3 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может принимать в качестве аргументов адреса IPv4 и IPv6 в произвольных комбинациях. Для каждого адреса мы выделяем место под структуруsctp_bindxнесмотря на то, что соответствующий аргументsockaddr_storageпредставляет собой упакованный список адресов (см. рис. 9.3). В результате мы расходуем зря некоторый объем памяти, но зато функция работает быстрее, потому что ей не приходится вычислять точный объем памяти и лишний раз обрабатывать список аргументов.sctp_bindxОбработка аргументовМы подготавливаем11-18к хранению номера порта в ASCII-представлении, имея в виду вызов нашей обертки дляportbuf, которая называетсяgetaddrinfo. Каждый адрес с номером порта мы передаемhost_serv, указывая константыhost_serv(протоколы IPv4 и IPv6) иAF_UNSPEC(протокол SCTP). Мы копируем первую возвращаемую структуруSOCK_SEQPACKET, игнорируя все остальные. Поскольку аргументами этой функции должны быть адреса в строковом представлении, а не имена, с каждым из которых может быть связано несколько адресов, это не вызывает проблем. Мы освобождаем буфер, увеличиваем количество адресов на единицу и перемещаем указатель на следующий элемент в упакованном массиве структурsockaddr.sockaddrВызов связывающей функцииУказатель устанавливается на начало буфера адресов, после чего вызывается функция19, в качестве аргументов которой используется раскодированный ранее набор адресов.sctp_bindx