У меня есть сценарий PHP CLI, который в основном написан как сервер чата для подключения клиентов чата (не спрашивайте меня, почему я делаю это на PHP, это еще одна история, ха-ха).
Мой скрипт использует функцию socket_select () для приостановки выполнения до тех пор, пока что-то не произойдет с сокетом, и в этот момент он просыпается, обрабатывает событие и ожидает до следующего события. Теперь есть некоторые рутинные задачи, которые мне нужно выполнять каждые 30 секунд или около того (проверьте, должны ли временные пользователи быть разблокированными, сохраните пользовательские базы данных, другие разные вещи).
Из того, что я могу сказать, PHP вообще не имеет большой поддержки многопоточности. Моей первой мыслью было сравнивать временную метку каждый раз, когда сокет генерирует событие и запускает программу снова, но это очень противоречиво, поскольку сервер вполне может бездействовать часами и не выполнять ни одной из моих процедур очистки.
Я натолкнулся на расширения PHP pcntl, и он позволяет мне назначить интервал времени для SIGALRM для отправки и выполнения функции при каждой отправке. Это кажется идеальным решением моей проблемы, однако pcntl_alarm () и socket_select () конфликтуют друг с другом довольно плохо. Каждый раз, когда запускается SIGALRM, с моим кодом управления сокетом происходят всякие сумасшедшие вещи.
Моя программа довольно длинная, поэтому я не могу опубликовать все это здесь, но это не должно иметь значения, так как я не верю, что делаю что-то не так в коде. Мой вопрос: есть ли способ для обработки SIGALRM в том же потоке, что и ожидающий socket_select ()? Если так, то как? Если нет, то каковы мои альтернативы здесь?
Вот некоторые результаты моей программы. Моя функция будильника просто выводит "Tick!" всякий раз, когда он вызывается, чтобы было легко узнать, когда что-то происходит. Это вывод (включая ошибки) после того, как он был отмечен 4 раза (не было никаких реальных попыток подключения к серверу, несмотря на то, что он говорит):
[05-28-10 @ 20:01:05] Сервер чата запущен на 192.168.1.28 порту 4050
[05-28-10 @ 20:01:05] Загружено 2 пользователей из файла
Примечание PHP: Неопределенное смещение: 0 в /home/danny/projects/PHPChatServ/ChatServ.php в строке 112
Предупреждение PHP: socket_select (): невозможно выбрать [4]: прерван системный вызов в /home/danny/projects/PHPChatServ/ChatServ.php в строке 116
[05-28-10 @ 20:01:15] Отметьте!
PHP Предупреждение: socket_accept (): невозможно принять входящее соединение [4]: прерван системный вызов в /home/danny/projects/PHPChatServ/ChatServ.php в строке 126
[05-28-10 @ 20:01:25] Отметьте!
Предупреждение PHP: socket_getpeername () ожидает, что параметр 1 будет ресурсом, логическое значение указано в /home/danny/projects/PHPChatServ/ChatServ.php в строке 129
[05-28-10 @ 20:01:25] Принятие подключения к сокету от
Примечание PHP: Неопределенное смещение: 1 в /home/danny/projects/PHPChatServ/ChatServ.php в строке 112
Предупреждение PHP: socket_select (): невозможно выбрать [4]: прерван системный вызов в /home/danny/projects/PHPChatServ/ChatServ.php в строке 116
[05-28-10 @ 20:01:35] Отметьте!
PHP Предупреждение: socket_accept (): невозможно принять входящее соединение [4]: прерван системный вызов в /home/danny/projects/PHPChatServ/ChatServ.php в строке 126
[05-28-10 @ 20:01:45] Отметьте!
Предупреждение PHP: socket_getpeername () ожидает, что параметр 1 будет ресурсом, логическое значение указано в /home/danny/projects/PHPChatServ/ChatServ.php в строке 129
[05-28-10 @ 20:01:45] Принятие сокетного соединения от
Примечание PHP: Неопределенное смещение: 2 в /home/danny/projects/PHPChatServ/ChatServ.php в строке 112