Грейсинг выключения сервера 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
от клиента.