За последние 24 часа нас посетили 17855 программистов и 1719 роботов. Сейчас ищет 881 программист ...

PHP - Ratchet WebSockets for PHP - мультипоточность

Тема в разделе "Прочие вопросы по PHP", создана пользователем phnmnn, 4 дек 2014.

  1. phnmnn

    phnmnn Новичок

    С нами с:
    4 дек 2014
    Сообщения:
    7
    Симпатии:
    0
    Добрый день.
    Я создал свой первый веб сокет как показано в примерах.
    Столкнулся с проблемой что вебсокет по сути однопоточный.. то есть если есть несколько клиентов ждущих ответа от сервера то они получает их по очереди, а не параллельно.

    Каким образом из Ratchet WebSockets for PHP можно получить многопоточный вебсокет, чтобы у каждого клиента мог обращаться к вебсокету не стоя в очереди.

    Спасибо
     
  2. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    при подключении клиента делать форк и обрабатывать клиента уже в отдельном процессе.
     
  3. phnmnn

    phnmnn Новичок

    С нами с:
    4 дек 2014
    Сообщения:
    7
    Симпатии:
    0
    Код (Text):
    1. class API implements MessageComponentInterface {
    2.  
    3. public function __construct() {
    4.  
    5. }
    6.  
    7. public function onOpen(ConnectionInterface $conn) {
    8.  
    9. }
    10.  
    11. public function onMessage(ConnectionInterface $from, $msg) {
    12.  
    13.      // store data in db
    14.      // some analysis (take several seconds)
    15.      // back answer to client
    16.  
    17.      //How to back answer to all client in parallel ??
    18. }
    19.  
    20. public function onClose(ConnectionInterface $conn) {
    21.  
    22.  
    23. }
    24.  
    25. public function onError(ConnectionInterface $conn, \Exception $e) {
    26.  
    27.  
    28. }
    29.  
    30.  
    31.  
    32. }
    никогда не работал с форком раньше.

    Вот пример кода, можно схематично изобразить как это должно выглядеть? спасибо
     
  4. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
     
  5. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    старт сценария
    определение "общего" массива данных
    открытие сокета
    уход в бесконечный "мастер"-цикл
    ожидание соединения
    прием соедиения
    форк
    если ненулевой идентификатор процесса - это мастер и далее к началу бесконечного цикла
    иначе это воркер и продолжаем работать с клиентом.
    определили "частный" массив данных
    туда-сюда с клиентом пообщались, закрыли клиентский сокет, отправили мастеру уведомление о своей смерти, стали зомби.

    вот так это схематично должно выглядеть. пожалуйста.

    Добавлено спустя 5 минут 26 секунд:
    ну как минимум пид у них будет разный поэтому увтерждение "совершенно идентичных" (читай тождественных) неверно в корне. к тому же у одного будет стек детей а у другого - сигнальный канал с родителем. то есть опять они нифига не идентичны. в общем автор тут погорячился.
     
  6. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Ratchet, он работает как мультиплексор. По-этому, да, любое блокирующее действие останавливает другие клиенты. Решения тут два - или, как сказали, форк. Но тут нужно эксперементировать как поведет себя умирающих PHP с открытыми соединениями... как бы он их не позакрывал.
    Второй вариант - разбираться, на что тратите время. Если вы общаетесь с базой данных, то переводить ее в асинхронный режим. Большинство драйверов в PHP уже это умеют.

    Добавлено спустя 3 минуты 33 секунды:
    Вы правда думаете, что на данном этапе объяснения теории данному человеку это уточнение ему что-то даст, кроме увеличения количества букв и потока ненужной ему пока информации? Вам поменьше нужно умничать. Побольше с людьми общаться.
     
  7. phnmnn

    phnmnn Новичок

    С нами с:
    4 дек 2014
    Сообщения:
    7
    Симпатии:
    0
    Долгая обработка запроса от клиента у меня как раз связана с тем что сервер ждет не появится ли определеная запись в базе данных в течение 5 секунд(например) от другого клиента . Если она есть сразу возвращает ответ клиент, если нет то ждет.

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

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Вам видимо нужно это читать http://socketo.me/docs/push
    Это более правильно, чем дергать в цикле базу, даже если удастся это сделать асинхронно.
     
  9. phnmnn

    phnmnn Новичок

    С нами с:
    4 дек 2014
    Сообщения:
    7
    Симпатии:
    0
    Сделал как вы сказали, все работает.

    Теперь такая проблема возникла.. Когда я закрываю терминал (ssh сессию), вебсокет закрывается.
    Каким образом можно заставить его постоянно работать. И как посмотреть из терминала запущен ли он, чтобы снова запустить его при надобности?

    Спасибо
     
  10. metadon

    metadon Активный пользователь

    С нами с:
    6 фев 2006
    Сообщения:
    779
    Симпатии:
    0
    А что в поиске забанили? Трудно поискать: как сделать чтобы программа работалата после выхода из терминала
     
  11. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    ну дык у вас же не даемон а просто скрипт который живет в консольке. консольку прихлопнули - скрипт умер.

    всё банально. даемону дать пид-файл. по крону или другим даемоном проверять этот пид-файл. если он перешел в другое состояние - признаем умершим, трём мусор, пробуем заново запустить. и обязательно обучить даемона всем сигналам системы.
     
  12. phnmnn

    phnmnn Новичок

    С нами с:
    4 дек 2014
    Сообщения:
    7
    Симпатии:
    0
    И еще такой вопрос.
    Код (Text):
    1. public function onMessage(ConnectionInterface $from, $msg) {
    2.  
    3.     $pid = pcntl_fork();
    4.     if ($pid == -1) {
    5.         $this->myPrint("cant create fork");
    6.     } else if ($pid) {
    7.  
    8.     } else {
    9.         // ..... $result
    10.         $from->send($result);
    11.         // $pid = getmypid();
    12.         // exit($pid);
    13.  
    14.     }
    15.  
    16. }
    Если я закрываю дочерний процесс то клиент не получает сообщения...

    Если их не закрывать то все работает но процессы плодяться

    [​IMG]

    пробовал закрывать так:
    Код (Text):
    1. function _exit() {
    2.     posix_kill(posix_getpid(), SIGTERM);
    3. }
    результат то же

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

    upd: http://mithrandir.ru/professional/php/php-daemons.html благодаре этой статье с демонами разобрался.
     
  13. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

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

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

    phnmnn Новичок

    С нами с:
    4 дек 2014
    Сообщения:
    7
    Симпатии:
    0
    Ganzal,

    Спасибо за помощь!

    А по проблеме отправки сообщения сокетом из дочернего процесса, перед смертью его можете что то посоветовать?
    Если закрываю процесс сообщение не отправляется...
     
  15. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    как делаете? и что в данном случае под сообщением подразумевается?
     
  16. phnmnn

    phnmnn Новичок

    С нами с:
    4 дек 2014
    Сообщения:
    7
    Симпатии:
    0
    1. клиент( на javascript) подключается к вебсокету.
    2. затем посылает сообщение вебсокету - json в виде строки.
    3. вебсокет получает сообщение от клиент,делает форк, в дочернем процессе, лезет в базу данных, и возвращает тоже - json в виде строки.
    4. закрываем дочерней процесс сразу после отправки собшения клиенту.

    Если не делаю 4 этап то все работает, если закрываю дочерней процесс сообщение не отправляется. Хотя закрытие в коде после отправки.
     
  17. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    есть мастер который слушает входящий сокет.
    пришел запрос от клиента у которого есть исходящий сокет. мастер форкнулся и готов обслуживать новый запрос на входящем сокете. ВСЁ с мастером.
    форк. принял подключение клиента и открыв клиентский входящий сокет и установив пир-ту-пир соединение между двумя сокетами - клиентским исходящим и своим клиентским входящим. чтение-запись-чтение-запись-итд-итп. закрыли клиентский входящий сокет (клиент на своей стороне считает соединение завершенным и закрывает свой исходящий сокет) и после этого уже ничего никуда не отправится. поэтому просто умираем.

    если у вас сообщения не ходят то в каком-то месте вы нарушаете логику работы сокетов.

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