Грейсинг выключения сервера Socket в Linux

Я хочу, чтобы вы могли прекратить прослушивание сокета сервера в Linux и убедиться, что все соединения, открытые с клиентской точки зрения, правильно обрабатываются и не закрываются внезапно (т.е. получают ECONNRESET).

т

sock = create_socket();
listen(sock, non_zero_backlog);
graceful_close(sock);

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

Ответ 1

Единственный рабочий способ сделать это (я нашел):

  • предотвратить accept() от добавления большего количества клиентов

  • есть список открытых сокетов где-то и ждать, пока они все правильно закрыты, что означает:

    • используя shutdown(), чтобы сообщить клиенту, что вы больше не будете работать в этом сокете

    • вызывать read() на некоторое время, чтобы убедиться, что все клиент отправил тем временем был вытащен

    • затем используя close(), чтобы освободить каждый клиентский сокет.

  • Затем можно безопасно close() прослушивающий сокет.

Вы можете (и должны) использовать таймаут, чтобы убедиться, что соединения в режиме ожидания не будут длиться вечно.

Ответ 2

Вы смотрите на ограничение API сокета TCP. Вы можете рассматривать ECONNRESET как версию сокета EOF, или вы можете реализовать протокол более высокого уровня по TCP, который информирует клиента о надвигающемся отключении.

Однако, если вы попробуете последнюю альтернативу, помните о неразрешимой проблеме двух армий, которая делает невозможным постепенное отключение в общем случае; это является частью мотивации для механизма сброса соединения TCP в его нынешнем виде. Даже если бы вы могли написать graceful_close() так, чтобы он работал большую часть времени, вам, вероятно, все равно придется иметь дело с ECONNRESET, если только процесс сервера не может ждать вечно, чтобы получить graceful_close_ack от клиента.