2012-04-13 3 views
2

У меня есть родительский процесс, который создает 2 серверных сокета и вызывает select(), чтобы ждать нового соединения. Когда соединение приходит, сообщение отправляется дочернему процессу (создается с помощью fork(), после создания сокетов серверов, поэтому они совместно используются).Почему select() в родительском процессе делает accept() непригодным в дочернем процессе?

У этого ребенка вызов accept() на серверный сокет не работает. Я получил ошибку EAGAIN (неблокирующий сокет). В то время как вызов accept() в основном процессе работает отлично.

Конечно, я не звоню accept() в основном процессе, я просто проверял, работает ли он, и это так.

Почему я не могу позвонить accept() в дочернем процессе после select() в родительском?

EDIT: Цель состоит в том, чтобы создать фиксированное количество рабочих (допустим, 8) для обработки клиентских подключений, как в модели предкара. Эти соединения будут длинными соединениями, а не HTTP. Цель состоит в том, чтобы установить баланс между рабочими.

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

Вот почему я делаю select() в родительском, а затем отправляю сообщение дочернему процессу, потому что хочу «выбрать», какой процесс будет обрабатывать новое соединение.

Сервер прослушивает более одного гнезда (по одному для SSL, один без), поэтому я использую select() и непосредственно не accept() в детских процессов, потому что я не accept() на тройники в моих детей рабочих могут.

+2

EAGAIN на самом деле не является ошибкой per sé, это означает, что вызов был неблокирующим, но соединение не было готово. Просто спите немного и попробуйте еще раз. Любая другая ошибка, чем EAGAIN, конечно, является фактической ошибкой. –

+0

Почему бы не назвать 'accept' первым перед вами fork? Специально, поскольку вы знаете, что это работает. –

+0

Я не понимаю, что вы делаете. Не могли бы вы высказать минимальный код, чтобы мы могли воспроизвести ваше наблюдение? – moooeeeep

ответ

3

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

  • Основной процесс (родительский) создает 2 сокеты сервера, Bind() и слушать() их (с и без SSL, например)
  • я создаю 8 детей процессы с вилкой(), так что они наследуют родительские сокеты
  • Основной процесс запускает select() в бесконечном цикле
  • Когда один из двух его гнезд доступен, он отправляет сообщение дочернему устройству по каналу. Ребенок определяется благодаря значению общей памяти, которое содержит текущее количество клиентов «в дочернем процессе». Выбирается процесс, который в настоящее время обрабатывает наименьшее количество клиентов.
  • Этот дочерний процесс затем вызывает accept() на сервере сокета (сокет, используемый между двумя проходит в трубе, так что ребенок знает, какой из них назвать accept() на)

Проблема заключалась в том, что мой родитель процесс сказал ребенку принять сокет и снова войти в цикл сразу же после этого, который он снова запускает select(). Но если ребенок еще не принял сокет, select() снова возвращается для того же соединения. Вот почему я получил ошибку EAGAIN, на самом деле я дважды звонил accept() (или больше в зависимости от скорость - условия межпроцессного горения)!

Решение состоит в том, чтобы дождаться, когда ребенок ответит на трубку, например: «Привет, я принял соединение, все в порядке!», А затем возвращается в цикл select().

Это прекрасно работает. Реализация в Python доступна здесь для любопытных: https://github.com/thibautd/Kiwi!

Смежные вопросы