2010-05-29 2 views
1

У меня есть скрипт PHP CLI, который в основном написан, который функционирует как сервер чата для клиентов чата для подключения (не спрашивайте меня, почему я делаю это на PHP, вот еще одна история ха-ха).PHP: Может ли pcntl_alarm() и socket_select() мирно существовать в той же теме?

В моем скрипте используется функция socket_select(), чтобы повесить исполнение, пока что-то не произойдет в сокете, после чего он просыпается, обрабатывает событие и ждет следующего события. Теперь есть некоторые рутинные задачи, которые мне нужно выполнять каждые 30 секунд или около того (проверьте, должны ли tempbanned пользователи быть незамкнутыми, сохранять пользовательские базы данных, другие разнообразные вещи).

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

Я столкнулся с расширениями pcntl PHP, и он позволяет мне назначать временной интервал для SIGALRM для отправки, а функция запускается каждый раз при ее отправке. Это похоже на идеальное решение моей проблемы, однако pcntl_alarm() и socket_select() сталкиваются друг с другом довольно плохо. Каждый раз, когда запускается SIGALRM, всевозможные сумасшедшие вещи происходят с моим кодом управления сокетами.

Моя программа довольно длинная, поэтому я не могу публиковать ее здесь, но это не имеет значения, поскольку я не верю, что я делаю что-то неправильное по коду. Мой вопрос: есть ли способ для SIGALRM обрабатываться в том же потоке, что и ожидающий socket_select()? Если да, то как? Если нет, то какие у меня альтернативы?

Вот некоторые результаты моей программы. Моя функция будильника выводит «Tick!». когда он призван, чтобы было легко рассказать, когда происходит материал. Это результат (включая ошибки) после того, как он сделал отметку 4 раза (не было реальных попыток подключиться к серверу, несмотря на то, что он говорит):

[05-28-10 @ 20:01:05 ] Chat сервер начал порт 192.168.1.28 4050

[05-28-10 @ 20:01:05] нагруженных 2 пользователей из файла

PHP Примечание: Undefined смещение: 0 в/Home/Danny/проектов /PHPChatServ/ChatServ.php в строке 112

PHP Предупреждение: socket_select(): невозможно выбрать [4]: ​​Прерванный системный вызов в/home/danny/pr ojects/PHPChatServ/ChatServ.php в строке 116

[05-28-10 @ 20:01:15] Tick!

PHP Предупреждение: socket_accept(): не может принимать входящие соединения [4]: ​​Прерванный системный вызов в /home/danny/projects/PHPChatServ/ChatServ.php на линии 126

[05-28-10 @ 20:01:25] Тик! РНР Внимание: socket_getpeername() ожидает параметр 1, чтобы быть ресурсом, логический приведены в /home/danny/projects/PHPChatServ/ChatServ.php на линии 129

[05-28-10 @ 20:01:25] Принимая гнездо для подключения от PHP Примечание: Undefined смещение: 1 в /home/danny/projects/PHPChatServ/ChatServ.php на линии 112

РНР Внимание: socket_select(): невозможно выбрать [4]: ​​прерванный системный вызов в/home/danny/projects/PHPChatServ/ChatServ.php on line 116

[05-28-10 @ 20:01:35] Отметьте!

PHP Предупреждение: socket_accept(): не может принимать входящие соединения [4]: ​​Прерванный системный вызов в /home/danny/projects/PHPChatServ/ChatServ.php на линии 126

[05-28-10 @ 20:01:45] Тик!

РНР Внимание: socket_getpeername() ожидает параметр 1, чтобы быть ресурсом, логический приведены в /home/danny/projects/PHPChatServ/ChatServ.php на линии 129

[05-28-10 @ 20:01: 45] Принимая гнездо подключения с

PHP Notice: Undefined смещение: 2 в /home/danny/projects/PHPChatServ/ChatServ.php на линии 112

ответ

2

pcntl_alarm и socket_select могут сосуществовать, но вы должны быть осознавая, как это сделать правильно.

В частности, если тревога отключается, пока socket_select() ждет, то после обработки сигнала тревоги socket_select() немедленно вернется с индикацией ошибки. Ошибка: «Прерванный системный вызов», что вы видите на выходе. Вам нужно специально проверить эту ошибку и повторить попытку socket_select().

В качестве альтернативы вы можете просто забыть об использовании будильника и вместо этого использовать тайм-аут socket_select(). Это параметр tv_sec - он дает таймаут в секундах, после чего возвращается socket_select(), даже если сокеты не готовы. Затем вы можете выполнять свою обычную обработку.

+0

Я считаю, что параметр tv_sec будет работать отлично, что я делаю – DWilliams