Изящное завершение работы серверного сокета в Linux
Я хочу иметь возможность перестать слушать на сокете сервера в Linux и убедиться, что все соединения, которые открыты с точки зрения клиента, правильно обрабатываются и не закрываются внезапно (т. Е. Получают ECONNRESET).
то есть:
sock = create_socket();
listen(sock, non_zero_backlog);
graceful_close(sock);
если будет достаточно вызова close() и обработки уже принятых сокетов accept'd, но могут быть открытые соединения в бэклоге ядра, которые будут внезапно закрыты, если вы вызовете close() на сокете сервера.
2 ответа
Единственный способ сделать это (что я нашел) - это:
предотвращать
accept()
от добавления большего количества клиентовиметь где-нибудь список открытых сокетов и ждать, пока они все не закроются должным образом, что означает:
с помощью
shutdown()
сказать клиенту, что вы больше не будете работать с этим сокетомвызов
read()
на некоторое время, чтобы убедиться, что все, что клиент отправил за это времязатем с помощью
close()
освободить каждый клиентский сокет.
ТОГДА можно смело
close()
гнездо для прослушивания.
Вы можете (и должны) использовать тайм-аут, чтобы убедиться, что простаивающие соединения не будут длиться вечно.
Вы смотрите на ограничение API сокета TCP. Вы можете посмотреть на ECONNRESET
как версия сокета EOF
или вы можете реализовать протокол более высокого уровня через TCP, который информирует клиента о надвигающемся разрыве соединения.
Однако, если вы попробуете последний вариант, помните о неразрешимой проблеме двух армий, которая делает невозможным постепенное отключение в общем случае; это является частью мотивации для механизма сброса соединения TCP в его нынешнем виде. Даже если бы ты мог написать graceful_close()
таким образом, который работал бы большую часть времени, вам, вероятно, все равно придется иметь дело с ECONNRESET
если процесс сервера не может ждать вечно, чтобы получить graceful_close_ack
от клиента.