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 Хотя ассоциация и была завершена, дескриптор сокета все равно закрыть нужно, чтобы освободить связанные с ним системные ресурсы.

Данный текст является ознакомительным фрагментом.