Обработка необоснованных отключений при использовании вилок и розеток

У меня есть сервер, который прослушивает сокет-соединения и выполняет различные виды действий, в зависимости от запроса. Одним из них являются долгоживущие запросы к базе данных, для которых сервер разветвляется.

Сервер хранит журнал всех активных дочерних элементов и всякий раз, когда его просят отключить, он убивает всех своих дочерних элементов перед выходом. Пару раз я сталкивался с ситуацией, когда сервер падал или был некорректно убит, что приводило к тому, что дочерний процесс становился сиротой. Если я попытаюсь вернуть сервер снова, он откажет, что прослушивающий сокет не может связываться, потому что этот адрес / порт уже связан.

Я ищу способ улучшить ситуацию такого рода, чтобы основной процесс сервера мог вернуться сразу же. Я пытался контролировать родительское существование от ребенка и выходить, как только его нет, но это только привело к появлению зомби-процессов, и сокет, кажется, все еще связан.

Сервер написан на Python, но любые объяснения или предложения на любом языке приветствуются.

3 ответа

Сделайте ваш сервер лидером группы процессов. В этом случае дети увольняются, когда выходит лидер группы.

Когда в Unix-подобной системе используется текстовый пользовательский интерфейс, сеансы используются для реализации сеансов входа в систему. Один процесс, лидер сеанса, взаимодействует с управляющим терминалом, чтобы гарантировать, что все программы завершаются, когда пользователь "вешает" соединение терминала. (Там, где отсутствует лидер сеанса, процессы в основной группе процессов терминала должны обрабатывать зависания.)

Используйте это в своем сокете перед вызовом listen():

int on = 1;
setsockopt (sockfd_wan, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));

Это позволяет вашей программе использовать этот сокет, даже если он был ранее случайно выбран другим исходящим TCP-соединением (не может происходить для портов <1024). Но это также должно помочь непосредственно с вашей проблемой!

Unrelated:

Может случиться и другое плохое: если ваши дети разветвлены, они наследуют КАЖДЫЙ открытый файловый дескриптор. Если они просто разветвляются и запускают другую долго работающую программу, они также будут иметь открытый дескриптор вашего прослушивающего сокета, так что он останется в использовании (узнайте с помощью команд lsof и netstat!)

Так что нужно назвать это:

int close_on_exec_on(int fd)
{
  return fcntl(fd, F_SETFD, FD_CLOEXEC);
}

close_on_exec_on(sockfd);

Но я никогда не пробовал его в основной программе, если он разветвляет childs, и он явно не поможет вам, потому что childs разветвляются, а не запускаются с exec.

Но имейте это в виду и в любом случае вызовите его на своем сокете прослушивания в основной программе! На случай, если вы запустите внешнюю программу

Возможно, когда вы разветвляетесь, откажитесь от дочернего, чтобы родительский процесс не был зарегистрированным в ОС родительским процессом. Родителю действительно нужно общаться с ребенком? Если нет, то это может быть вариант.

Вы можете отслеживать дочерние процессы, но другим способом. Вы больше не будете получать события SIGCHLD.

Другие вопросы по тегам