Книга: UNIX: разработка сетевых приложений

10.7. Управление завершением соединения

10.7. Управление завершением соединения

В наших примерах на клиента была возложена ответственность по завершению ассоциации, для чего ему приходилось закрывать сокет. Но закрытие сокета не всегда является желаемой операцией с точки зрения приложения. Кроме того, серверу не нужно оставлять ассоциацию открытой после отправки эхо-ответа. В описанных ситуациях применяются альтернативные механизмы завершения ассоциации. Для сокетов типа «один-ко-многим» доступно два метода: корректное и аварийное закрытие.

Если сервер хочет закрыть ассоциацию после отправки сообщения, он должен добавить флаг MSG_EOF в это сообщение, поместив его в поле sinfo_flags структуры sctp_sndrcvinfo. Этот флаг закрывает ассоциацию после подтверждения приема отсылаемого сообщения. Альтернативный метод состоит в установке флага MSG_ABORT в том же поле sinfo_flags. При этом происходит немедленное закрытие ассоциации с отправкой порции ABORT (аналог TCP-сегмента RST). Данные, находящиеся в буфере отправки, сбрасываются. Однако закрытие сеанса SCTP порцией ABORT не приводит к негативным последствиям типа пропущенного состояния TIME_WAIT, как это происходит в TCP. В листинге 10.7 показана новая версия эхо-сервера, инициирующая корректное завершение соединения одновременно с отправкой эхо-ответа клиенту. В листинге 10.8 показана версия клиента, отправляющая порцию ABORT перед закрытием сокета.

Листинг 10.7. Сервер, закрывающий ассоциацию после отправки ответа

//sctp/sctpserv03.c
25 for (;;) {
26  len = sizeof(struct sockaddr_in);
27  rd_sz = Sctp_recvmsg(sock_fd, readbuf, sizeof(readbuf),
28   (SA*)&cliaddr, &len, &sri, &msg_flags);
29  if (stream_increment) {
30   sri.sinfo_stream++;
31   if (sri.sinfo_stream >=
32    sctp_get_no_strms(sock_fd, (SA*)&cliaddr, len))
33    sri.sinfo_stream = 0;
34  }
35  Sctp_sendmsg(sock_fd, readbuf, rd_sz,
36   (SA*)&cliaddr, len,
37   sri.sinfo_ppid,
38   (sri.sinfo_flags | MSG_EOF), sri.sinfo_stream, 0, 0);
39 }

Отправка ответа с закрытием ассоциации

38 Изменение кода сервера состоит в том, что мы добавляем флаг MSG_EOF к прочим флагам в вызове sctp_sendmsg операцией логического ИЛИ. Благодаря этому сервер закрывает ассоциацию после подтверждения доставки сообщения.

Листинг 10.8. Клиент, выполняющий аварийное закрытие ассоциации

//sctp/sctpclient02.c
25 if (echo_to_all == 0)
26  sctpstr_cli(stdin, sock_fd, (SA*)&servaddr, sizeof(servaddr));
27 else
28  sctpstr_cli_echoall(stdin, sock_fd, (SA*)&servaddr,
29   sizeof(servaddr));
30 strcpy(byemsg, "goodbye");
31 Sctp_sendmsg(sock_fd, byemsg, strlen(byemsg),
32  (SA*)&servaddr, sizeof(servaddr), 0, MSG_ABORT, 0, 0, 0);
33 Close(sock_fd);

Аварийное закрытие ассоциации

30-32 Клиент подготавливает сообщение об аварийном закрытии ассоциации, вызванном пользовательской ошибкой. Затем функция sctp_sendmsg вызывается с флагом MSG_ABORT. При этом отправляется порция данных ABORT, что приводит к немедленному закрытию ассоциации. В порцию данных включается код пользовательской ошибки и сообщение («goodbye») в поле причины ошибки вышележащего уровня.

Закрытие дескриптора сокета

33 Хотя ассоциация и была завершена, дескриптор сокета все равно закрыть нужно, чтобы освободить связанные с ним системные ресурсы.

Оглавление книги


Генерация: 1.290. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз