9.2. На стороне сервера выполняется автоматическое закрытие после закрытия ассоциации клиентом. SCTP не поддерживает состояние неполного закрытия, поэтому когда клиент вызывает
close
, все подготовленные сервером данные сбрасываются и ассоциация закрывается.
9.3. Сокет типа «один-к-одному» требует вызова
connect
, поэтому когда собеседнику отсылается сегмент COOKIE, никаких данных в буфере отправки быть еще не может. Сокет типа «один-ко-многим» допускает отправку данных с одновременной установкой соединения. Поэтому сегмент COOKIE в этом случае может быть совмещен с сегментом DATA.
9.4. Собеседник, с которым устанавливается ассоциация, может прислать данные только в том случае, если у него будет готов сегмент DATA до того, как соединение будет установлено, то есть если на обеих сторонах используются сокеты типа «один-ко-многим» и каждая сторона выполняет операцию send с неявной установкой соединения. Такой процесс установки ассоциации называется коллизией пакетов INIT и подробно описывается в главе 4 [117].
9.5. В некоторых случаях не все связанные адреса могут быть переданы собеседнику. В частности, если приложение связало с сокетом как частные, так и общие IP-адреса, собеседник получит информацию только об общих IP-адресах. Еще одним примером являются локальные в рамках канала адреса IPv6, которые не обязательно сообщаются собеседнику.
Глава 10
10.1 Если функция
sctp_sendmsg
возвращает ошибку, сообщение не будет отправлено, а приложение вызовет функцию
sctp_recvmsg
и заблокируется в ней навсегда, ожидая ответного сообщения, которое никогда не придет.
Чтобы избежать этой неприятности, нужно проверять коды возврата. Если при отправке возникла ошибка, клиент не должен пытаться получить ответ. Ему следует просто сообщить о возникшей ошибке.
Если функция
sctp_recvmsg
вернет ошибку, никаких сообщений получено не будет, но сервер все равно попытается отправить сообщение, что может привести к установлению ассоциации. Для предотвращения этого следует проверять код ошибки и, в зависимости от его значения, сообщать об ошибке и закрывать сокет (при этой операции также может быть возвращена ошибка) или повторно вызывать
sctp_recvmsg
.
10.2. Если сервер получает запрос и завершает работу, клиент (в его нынешней форме) зависает навечно в ожидании ответа сервера. Клиенту следует включить доставку уведомлений о событиях для данной ассоциации. Когда сервер завершит работу, клиент получит соответствующее сообщение и сможет принять какие-либо меры, например связаться с другим сервером. Альтернативным решением может быть установка таймера и завершение работы по истечении времени ожидания.
10.3. Чтобы каждая порция данных была помещена в свой пакет, мы установили размер сообщения 800 байт. Более правильным решением будет получение значения параметра сокета
SCTP_MAXSEG
для определения размера данных, помещающихся в один пакет.
10.4. Алгоритм Нагла (управляемый параметром сокета
SCTP_NODELAY
, см. раздел 7.10) вызывает проблемы только при передаче данных небольших объемов. Если данные передаются порциями такого размера, что SCTP вынужден передавать их немедленно, никакого замедления быть не может. Установка небольшого размера
out_sz
исказит результаты, потому что в некоторых случаях передача будет задерживаться до получения выборочных уведомлений от собеседника. Поэтому при передаче данных небольшого размера алгоритм Нагла следует отключать.
10.5. Если приложение устанавливает ассоциацию и изменяет количество потоков, количество потоков в данной ассоциации не меняется. Количество потоков может быть задано только для новых ассоциаций, но не для существующих.
Сокет типа «один-ко-многим» позволяет устанавливать ассоциации неявно. Для изменения параметров ассоциации необходимо вызвать
sendmsg
со вспомогательными данными. Фактически при этом обязательно использовать неявное установление ассоциации.
Глава 11
11.1. В листинге Д.4 приведена программа, вызывающая функцию
gethostbyaddr
.
Листинг Д.4. Изменение листинга 11.1 для вызова функции gethostbyaddr
//names/hostent2.c
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 char *ptr, **pptr;
6 char str[INET6_ADDRSTRLEN];
7 struct hostent *hptr;
8 while (--argc > 0) {
9 ptr = *++argv;
10 if ( (hptr = gethostbyname(ptr)) == NULL) {
11 err_msg("gethostbyname error for host: %s: %s",
12 ptr, hstrerror(h_errno));
13 continue;
14 }
15 printf("official hostname: %s\n", hptr->h_name);
16 for (pptr = hptr->h_aliases; *pptr != NULL; pptr++)
17 printf(" alias: %s\n", *pptr);
18 switch (hptr->h_addrtype) {
19 case AF_INET:
20 #ifdef AF_INET6
21 case AF_INET6:
22 #endif
23 pptr = hptr->h_addr_list;
24 for (; *pptr != NULL; pptr++) {
25 printf("\taddress: %s\n",
26 Inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));
27 if ((hptr = gethostbyaddr(*pptr, hptr->h_length,
28 ptr->h_addrtype)) == NULL)
29 printf("\t(gethostbyaddr failed)\n");
30 else if (hptr->h_name != NULL)
31 printf("\tname = %s\n", hptr->h_name);
32 else
33 printf("\t(no hostname returned by gethostbyaddr)\n");
34 }
35 break;
36 default:
37 err_ret("unknown address type");
38 break;