Обработка необоснованных отключений при использовании вилок и розеток - PullRequest
3 голосов
/ 15 мая 2009

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

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

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

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

Ответы [ 3 ]

2 голосов
/ 15 мая 2009

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

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

1 голос
/ 15 мая 2009

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

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

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

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.

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

0 голосов
/ 15 мая 2009

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

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

...