Вебсокеты на php. Выбираем вебсокет-сервер

    Давным-давно я публиковал статью на хабре, как написать свой вебсокет-сервер с нуля. Статья переросла в библиотеку. Несколько месяцев я занимался её развитием, ещё несколько лет — поддержкой и багфиксом. Написал модуль интеграции с yii2. Какой-то энтузиаст написал интеграцию с laravel. Моя библиотека совместима с php7. Недавно я решил отказаться от её дальнейшей поддержки (причины ниже), поэтому хочу помочь её пользователям перейти на другую библиотеку.



    Прежде чем начать писать свой вебсокет-сервер, я выбирал из готовых продуктов, и на тот момент их было всего два: phpdaemon и ratchet.

    phpdaemon


    1400 звёзд на гитхабе

    • зависит от установки библиотеки libevent
    • протоколы: HTTP, FastCGI, FlashPolicy, Ident, Socks4/5.

    Ratchet


    3600 звёзд на гитхабе

    • тянет за собой около десятка зависимостей
    • протоколы: websocket, http, wamp
    • поддержка windows
    • нет ssl

    Эти библиотеки были очень монструозны и при этом не соответствовали моим внутренним требованиям:

    • отсутствие зависимостей
    • наличие таймеров

    Таймеры мне нужны были для написания игры на вебсокетах для расчёта взаимодействий между всеми пользователями каждые 0.05 секунды.

    В итоге я написал библиотеку для себя и поделился ею с сообществом на гитхабе. Сделал несколько демок (в том числе игру «танчики»). Переписал стороннюю игру (с разрешения авторов) с node.js на свою библиотеку. Делал нагрузочное тестирование. Демки работали годами без перезагрузки. Старался отвечать на тикеты в течения дня. Всё это показывало, что моя библиотека может быть использована на продакшене и многие её использовали.

    Была единственная проблема. Мне хватало моей библиотеки для использования в своих проектах, а вот другим нет. Они хотели, чтобы я её развивал, а мне это было не нужно. Кому-то требовалась поддержка windows, а кому-то ssl, pg_notify, safari, pthreads и многое другое. Открытые тикеты с запросами на реализацию различного функционала висят годами.

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

    Workerman


    4500 звёзд на гитхабе

    • отсутствие зависимостей
    • протоколы: websocket, http/https, tcp, сustom
    • поддержка таймеров
    • интеграция с react-компонентами
    • поддержка windows

    Первый его релиз был ещё два года назад, но почему-то всё новые и новые люди начинали пользоваться моей библиотекой для новых проектов. Я ещё могу понять, что ею пользуются на старых проектах (работает — не трогай), но на новых… — для меня это была загадка.

    Если загуглить «php websocket», то первая страница — это моя статья на Хабре, а вторая — «Ratchet», который кому-то может показаться сложным и он выберет из-за этого мою библиотеку или вообще откажется от идеи делать вебсокеты.

    Что ж, пришло время исправить эту досадную ошибку и донести до как можно большего количества людей о существовании такой библиотеки как Workerman и привести несколько примеров по её использованию.

    На главной странице проекта в гитхабе уже есть несколько примеров. Рассмотрим один из них:

    websocket server
    <?php
    require_once __DIR__ . '/vendor/autoload.php';
    use Workerman\Worker;
    
    // Create a Websocket server
    $ws_worker = new Worker("websocket://0.0.0.0:8000");
    
    // 4 processes
    $ws_worker->count = 4;
    
    // Emitted when new connection come
    $ws_worker->onConnect = function($connection)
    {
        echo "New connection\n";
     };
    
    // Emitted when data received
    $ws_worker->onMessage = function($connection, $data)
    {
        // Send hello $data
        $connection->send('hello ' . $data);
    };
    
    // Emitted when connection closed
    $ws_worker->onClose = function($connection)
    {
        echo "Connection closed\n";
    };
    
    // Run worker
    Worker::runAll();
    tcp server
    <?php
    require_once __DIR__ . '/vendor/autoload.php';
    use Workerman\Worker;
    
    // #### create socket and listen 1234 port ####
    $tcp_worker = new Worker("tcp://0.0.0.0:1234");
    
    // 4 processes
    $tcp_worker->count = 4;
    
    // Emitted when new connection come
    $tcp_worker->onConnect = function($connection)
    {
        echo "New Connection\n";
    };
    
    // Emitted when data received
    $tcp_worker->onMessage = function($connection, $data)
    {
        // send data to client
        $connection->send("hello $data \n");
    };
    
    // Emitted when new connection come
    $tcp_worker->onClose = function($connection)
    {
        echo "Connection closed\n";
    };
    
    Worker::runAll();

    Чтобы запустить пример, нужно установить workerwan: composer require workerman/workerman
    Пример можно запустить с помощью команды php test.php start и в консоли мы увидим:
    ----------------------- WORKERMAN -----------------------------
    Workerman version:3.3.6 PHP version:7.0.15-0ubuntu0.16.10.4
    ------------------------ WORKERS -------------------------------
    user worker listen processes status
    morozovsk none websocket://0.0.0.0:8000 1 [OK]
    ----------------------------------------------------------------
    Все команды workerman:
    php test.php start
    php test.php start -d -демонизировать скрипт
    php test.php status
    php test.php stop
    php test.php restart
    php test.php restart -d
    php test.php reload

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

    Например:

    • пользователь #1 лайкает фотографию пользователя #2 и мы хотим отправить пользователю #2 об этом уведомление, если он сейчас на сайте.
    • на сайте появилось новое объявление и мы хотим отправить уведомление нашему модератору,
      чтобы он его проверил

    Из двух примеров выше можно собрать один, который будет делать то что нам нужно:

    Отправка сообщения одному пользователю:
    код сервера server.php:

    <?php
    require_once __DIR__ . '/vendor/autoload.php';
    use Workerman\Worker;
    
    // массив для связи соединения пользователя и необходимого нам параметра
    $users = [];
    
    // создаём ws-сервер, к которому будут подключаться все наши пользователи
    $ws_worker = new Worker("websocket://0.0.0.0:8000");
    // создаём обработчик, который будет выполняться при запуске ws-сервера
    $ws_worker->onWorkerStart = function() use (&$users)
    {
        // создаём локальный tcp-сервер, чтобы отправлять на него сообщения из кода нашего сайта
        $inner_tcp_worker = new Worker("tcp://127.0.0.1:1234");
        // создаём обработчик сообщений, который будет срабатывать,
        // когда на локальный tcp-сокет приходит сообщение
        $inner_tcp_worker->onMessage = function($connection, $data) use (&$users) {
            $data = json_decode($data);
            // отправляем сообщение пользователю по userId
            if (isset($users[$data->user])) {
                $webconnection = $users[$data->user];
                $webconnection->send($data->message);
            }
        };
        $inner_tcp_worker->listen();
    };
    
    $ws_worker->onConnect = function($connection) use (&$users)
    {
        $connection->onWebSocketConnect = function($connection) use (&$users)
        {
            // при подключении нового пользователя сохраняем get-параметр, который же сами и передали со страницы сайта
            $users[$_GET['user']] = $connection;
            // вместо get-параметра можно также использовать параметр из cookie, например $_COOKIE['PHPSESSID']
        };
    };
    
    $ws_worker->onClose = function($connection) use(&$users)
    {
        // удаляем параметр при отключении пользователя
        $user = array_search($connection, $users);
        unset($users[$user]);
    };
    
    // Run worker
    Worker::runAll();

    код клиента client.html:

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
        <script>
            ws = new WebSocket("ws://127.0.0.1:8000/?user=tester01");
            ws.onmessage = function(evt) {alert(evt.data);};
        </script>
    </head>
    </html>

    код отправки сообщений с нашего сайта send.php:

    <?php
    $localsocket = 'tcp://127.0.0.1:1234';
    $user = 'tester01';
    $message = 'test';
    
    // соединяемся с локальным tcp-сервером
    $instance = stream_socket_client($localsocket);
    // отправляем сообщение
    fwrite($instance, json_encode(['user' => $user, 'message' => $message])  . "\n");

    Справедливости ради я решил написать такой же пример для ratchet, но документация мне не помогла, как 3 года назад. Зато на stackoverflow предложили немного костыльный, но рабочий вариант: соединяться из своего php-скрипта по ws-соединению. Конечно это не так же просто как соединиться с tcp-сокетом с помощью stream_socket_client и отправить сообщение с помощью fwrite. Но уже что-то.

    Плюс ещё остался для меня незакрытый вопрос: поддерживает ли ratchet возможность запуска нескольких воркеров и если да, то как в таком случае отправлять сообщение одному пользователю, ведь не понятно на каком он воркере. На workerman это можно сделать так.

    В общем, я выбрал для себя библиотеку Workerman и рекомендую переходить на неё пользователям моей библиотеки. Все примеры лежат на гитхабе.

    Update: в комментариях рекомендуют swoole. Я натыкался на эту библиотеку ранее, но у меня сложилось ложное впечатление, что что она не поддерживает php7 и после этого она выпала из моего круга зрения. А зря. Интересная библиотека.
    Что вы используете для вебсокетов на сервере?

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 55
    • 0

      Ещё Swoole потеряли

      • НЛО прилетело и опубликовало эту надпись здесь
        • 0

          Преимущество у Go перед PHP ровно одно — это скорость. А какие ещё, раз уж вы говорите об "уйме"? По-мне, так наоборот.

          • НЛО прилетело и опубликовало эту надпись здесь
            • +1
              1. Это преимущество высосано из пальца, будем чествными.
              2. Это не преимущество, под пых их на несколько порядков больше.
              3. Зависит от реализации, конечно же, но в целом да, вы повторили мой пункт о скорости.
              4. Тот же самый пункт о скорости.

              В целом, кроме повтора тезиса "он быстрее" я не услышал никаких реальных оправданий его использования. Ну разве, только "он мне нравится", лично для меня это был самый убедительный аргумент. Т.к. язык, на котором нравится писать будет на порядок профитнее в умелых руках. Но это уже сугубо личное для каждого.


              Если постараться оценивать объективно, то пых и мощнее как язык, и экосистема в "веб-сфере" у него на порядок взрослее, и при базе на том же swoole, есть подозрения, что будет побыстрее большинства реализаций на Go, но это вообще не точно =)

              • 0
                «На порядок» = «в 10 раз». «Несколько порядков» = «в 100 раз», «в 1000 раз» и т.д. На будущее )
              • 0
                Лично меня смущает в переходе на го, не то, что птреды сторонние, ибо написаны Ваткинсом, который дофига в пхп вложил, не тем, что php резкий как незнаючто с 7ой версии, а то, что я не хочу становиться автором какой-нить навороченой либы для, например, каких-нить офисных документов… Ну, короче говоря, боязнь недостатка пакетов.
            • 0
              Тоже были порывы использовать pthreads. Но показалось хлопотным собирать php с zts постоянно. Но потом нам стало очевидным, что лучший способ параллелить задачи на php – очерди. Тем более есть такие прекрасные решения как beanstalk и rabbitmq.
            • –1
              ssl в ratchet завезли, но в еще не выпущеной ветке 0.4 (https://github.com/ratchetphp/Ratchet/commit/369227dc1c0e5e016e729d8ab4789a0fd0ba85e4)
              • 0
                А ProxyPass через апач вроде хорошо работает, и более простое решение имхо, особенно учитывая certbot
              • +1
                существует еще https://github.com/amphp/socket
                • 0
                  Ну это типа react'а, но поверх надо же еще веб-сокеты нагородить. Проще воспольльзоваться либой где уже есть этот функционал? Хотя как сокет это имхо очень прилично, но вот именно я не разобрался нормально, мне показалось, что сложней чем реакт. Я еще подумал, что проще тогда swoole.
                  • 0
                    виноват, слегка попутал со ссылкой
                    вот правильная — https://github.com/amphp/websocket
                    • 0
                      О, а я чет не стал искать, но уже всё есть, круто. Я сильно не вдавался в детали, посмотрел несколько примеров и мне кажется, что на колбэках как-то попроще будет, чем на елде выезжать :)
                      • +1

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


                        Так что учитывая всё это, я отдаю свой голос за React-based штукенции и даже не по причине йилдов, а просто код кажется более опрятным и читаемым, нежели пачка хелпер-функций ядра.

                        • 0
                          Да Amp вообще довольно дикая штука и написана большей половиной в хипстерском функциональном стиле

                          а можно пример? бегло пробежался по репозиториям — вроде все норм
                          • 0

                            Прям самое сердце этой либы: https://github.com/amphp/amp/blob/master/lib/functions.php Сейчас уже поопрятнее стало, с год назад вообще жуть творилась в этом файлике. Тысяча строк функций и процедурок.

                            • +1

                              Сейчас — обычная либа для асинхронности. Ни вижу ничего особо страшного, всего-то сделали аналог async/await через генераторы. Обычное дело для языков, где еще нет async/await, но уже есть генераторы. Через это прошли Python, C# и Javascript. Теперь вот очередь PHP.


                              Вот год назад, согласен — был кошмар. Только не надо называть таку свалку из функций "функциональным стилем" — в ФП любят чистые функции, а там первая же функция — с сайд-эффектом.

                              • 0

                                "функциональный стиль" я для красного словца упомянул с некоторой толикой иронии над JS. Нынче просто они любят подобную шляпу разводить и считают это нормой. Правда, в защиту можно сказать, что почти всегда она не уезжает за пределы модуля, но не суть. Надеюсь перерастут, как PHP в своё время, исходники какого-нибудь Ангулара почти что вменяемые, даже. Далеко не уровня Symfony или Laravel, но некоторый прогресс есть.


                                Ну и смотрели\использовали эту либу в продакшене как раз год назад примерно, вот и запомнился этот файлик и любовь мейнтейнеров к километровй кучке функций. Потом забили болт и переехали на Газзл, т.к. на тот момент она (библиотека Amp, а точнее сборка Artax) все логи спамила ошибками (которые гасятся через собаку, что не отменяет наличие самих сообщений об ошибках). Сейчас, к слову, они тоже остались, но не в таком количестве, конечно.

                • +2
                  Да, есть еще Swoole, но вот мы не используем его ибо у него с таск-воркерами (как нам показалось) странно сделано (жеско задается кол-во воркеров только при старте и, если передать таск несуществующему воркеру, то будет капец). Ну, а в целом Swoole – первый кандидат. Про него даже писали (точно не помню где), что из php сделали nodejs.
                  А вообще мы используем Ratchet. А схема работы в тяжелых случаях такая. Сам WS-сервер работает как шина, тоесть только передает сообщения. Ну и вот когда, например, приходит rpc-вызов на тяжелый таск, то это сообщение отправляется в очередь. Собственно это – элемент масштабирования. Можно поднять сколько надо воркеров, да еще и на разных серверах, если не будет хватать «сработки» при текущем количестве консумеров.
                  Для нас было самым большим открытием – это как вернуть ответ. Сначала консумер сообщался с ws-сервером по ws же протоколу. Но так мы имеем мега оверхэд по вермени затрачиваемому на само соединение. Особенно это заметно когда передается очень много сообщений на ws. Надо было как-то упростить схему. После продолжительных поисков был найден React Child Process Component. Он решил все проблемы с производительностью. И ответ теперь возвращается так: В loop react'а добавляется дочерний процесс, который поднимает ratchet же tcp-сервер. Тоесть консумер передает ответ через небольшую обертку над fsockopen на tcp сервер, который является процессом петли ws сервера и ему (дочернему процессу) остается только выдать сообщение в stdout и он попадет в onData обработчик дочернего процесса. А тут уже можно выбрать соединение и отправить ответ.
                  Тут остается только не забывать передавать sigterm на дочерние процессы-серверы-слушатели ответов, когда гасите сервер. Да, тут еще подоспела новая возможность PHP – pcntl_async_signals(). Специально для ratchet'а наверно писали, для диспатчинга в нем сигналов :)
                  Собственно поэтому и используем Ratchet, ибо подходит хорошо по производительности и степени удобства при конструировании сервера.
                  • –1

                    А через очередь ответ не передать никак?

                    • 0
                      Через очередь в ту же самую петлю событий, ответить в тот же сокет, который прислал запрос? То есть, тут вопрос в том, как в петлю событий добавить прослушку сокетов ws и amqp?
                      • 0

                        Ну, должен же тут быть какой-то способ. Вряд ли вы — первый кому захотелось обрабатывать ws и amqp в одном цикле.

                        • 0
                          Так наверняка на всех этих либах есть способ, но вот я считаю, что он, в смысле понимания, должен быть прост, а, в смысле скорости, не уступать другим решениям. Мне показалось что ратчет поверх реакта с дочерними процессами в петле событий – это самое и быстрое и простое одновременно. То есть, баланс скорости и простоты соблюден хорошо.
                          А еще, это дает свободу творчества :) Можно в этом дочернем процессе что угодно сделать. Хоть еще дочерних процессов напихать, каждый из которых сам сокет сервер. Кароче, как я и говорил, понятное и производительное решение.
                          • 0

                            Э… а что сложного в подходе вида "вот ws-сокет, вот amqp-сокет, вот мы их слушаем в цикле"?

                            • 0
                              Теоретически – ничего. Но это надо уметь напрограмировать так, что бы моск не вытек. Надо еще, помимо того, что добавить второй сокет на прослушку, понимать начать AMQP протокол (ну или любой другой, то есть, данные из сокета надо как-то же обрабатывать). Поэтому, нужны знания stream_socket_client и прочих функций или их оберток в той либе, которую вы используете. А тут получается, что дополнительные процессы добавляются в петлю, посредством прослушки stdout процесса. То есть, тут теория еще проще. Мы знаем, что слушаем появление данных, да еще и в красивой и удобной обертке. Я бы сравнил это с maven :) Плагины писать просто и можно делать на любом другом языке, ибо общение между плагинами и maven идет через stdout/stdin, если я не ошибаюсь. Вы понимаете преимущество возможности запустить процесс и слушать его stdput? Это же не обязательно может быть php, а, например, тот же го.
                              • 0

                                В том же цикле что и сокеты? Вы понимаете, что stdout процесса сильнее отличается от сокета чем amqp от ws?

                                • 0
                                  Да я-то про это и говорю, что не напрямую подключать заморочки, а подключать процессы, которые сами по себе могут быть чем угодно: сокетным сервером, который консумит amqp или квэрит данные из бд, или еще чем угодно и на чем угодно написаным, хоть на джаве, хоть на го… Ну вы поняли. Главное, что бы сам вебсокет оставался тупой шиной с легким подключением этих процессов. Это, заметте, быстрая и простая передача данных. Вот пример (я его еще в другом ответе ниже оставил): gist
                                  • 0

                                    Перечитал ваш комментарий три раза, но так и не понял.

                                    • 0
                                      Читайте ниже/дальше, там тоже самое да потому же, но другими словами
                          • 0
                            Бесспорно, вы красиво всё добавили в петлю, но:
                            — Это дополнительные либы
                            — Дополнительная теория
                            А что, если (тфутфуконечно) начнется усложение, увеличение нагрузки?
                            Надо знать как пользоваться \React\Promise\all, \Bunny\Async\Client, React\ZMQ\Context…
                            Не проще ли как-то так?
                            Как мне кажется, это более универсально. Я имею в виду добавление получения данных откуда-то в сокет.
                            • +1

                              Надо сказать, что минусы применимы и к вашему методу :)


                              • Дополнительная теория (реализация очень близка к моей)
                              • Надо знать как пользоваться React\ChildProcess\Process
                              • 0
                                С одной стороны вы правы, что надо знать «модуль» реакта, но в моем примере минус исчислимый – один, а в вашем примере, количество минусов может варьироваться в зависимости от того, что надо подключать к петле событий, тоесть:
                                — Теория/абстракции несравнимо проще (либо промисы/контексты/корутины/елды/ватева, либо in/out/err выхлоп процесса)
                                — Универсальность: можно подключить программу на любом языке, которая являться может чем угодно

                                Мне кажется или мы про Яблоки vs. Апельсины? :)
                                • 0

                                  Видите ли — дочерний процесс, он не из воздуха берется. Его тоже еще надо написать.


                                  Если вам дочерний процесс достался от другого разработчика — то, конечно же, проще запустить его как вы показали. Но если стоит задача переслать запрос от ws-клиента в amqp-очередь, а потом вернуть клиенту ответ — то проще обойтись без дочернего процесса: будет на 1 требующий изучения слой меньше.

                                  • 0
                                    На один ли меньше? Надо «подключить» к петле промис/контекст/корутину/елду или как там называется абстракция которую запрограммировали разработчики, что бы подключить реакцию на данные из сокета… В общем не меньше. Подключать придется. Но можно изучать как подключать каждое что там надо подключить или 1 метод. Поэтому я и считаю, что это проще/меньше теории и универсальней.
                                    • 0

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


                                      PS надоело читать ругательства вместо аргументов. Ловите минус в карму за "елду".

                                      • 0
                                        Это в теории абстракций две. Но разработчики либ могут их добвить/назвать по другому – больше теории.

                                        И какая разница, звОним мы или звонИм? Дозваниваемся же…
                                        • 0

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

                                      • 0
                                        В общем, суть не в том, что делает сам процесс, а в методе подключения реакции на данные в сервер. Мы изначально не разделили понятия. Я говорю про то, как подключить данные, а не как получать, когда они придут.
                                    • 0
                                      Мне кажется или мы про Яблоки vs. Апельсины? :)

                                      Весьма вероятно :)


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

                                      • 0
                                        Вы же знаете, что подключаете? Скрипт, который вы написали или сторонняя программа через обертку? В любом случае, не стоит конечно подключать что-то абсолютно не имея представления о том что там идет в вывод…

                                        На счет ошибок: еще есть stderr.

                                        На счет выпадения скрипта полностью. Есть возможность сделать так:
                                        $process->on('exit', function($exitCode, $termSignal) use ($process) {
                                        $process->start($server->loop);
                                        // или через фабрику
                                        });
                                        А в целом конечно лучше через обертку запускать (хотя это тоже под большим вопросом), которая сама будет там ответственна за перезапуск отвалившихся частей.
                                        Полагаю, лучше всё это на практике потестить.
                                        • +1

                                          И тут мы пришли к тому, что вам писал mayorovp. На один слой больше за счет такой вот обертки.
                                          Либо имеем нарушение принципа единственной ответственности, когда вебсокет сервер у нас еще занимается парсингом вывода и перезапуском упавших процессов.

                                          • –1
                                            «нарушение принципа единственной ответственности»
                                            Вебсокет сервер при методе, который я описываю, продолжает выполнять 1 роль – быть тупой шиной и перегонять данные от бэкенда к клиентам.

                                            «парсингом вывода»
                                            Это делают процессы, которые он запускает

                                            «и перезапуском упавших процессов»
                                            По этой де логике можно сказать, что, да, мы нарушаем принцип единой ответственности ибо сервер реагирует не только на ondata, но и на onopen, onclose, onerror, вызывает методы контроллеров при событиях…

                                            Либо мы не понимаем друг-друга, либо вы – знатные тролли, господа :)
                        • +1
                          Ещё есть voryx/thruway. Поддерживает WAMPv2. Бандл для симфони.
                          • 0
                            Ну, это вообще-то либа с WAMP-роутером и клиентами, а не чисто веб-сокет.
                            Для вебсокета, она как раз использует Ratchet (как один из возможных транспортов).
                            • 0
                              Да, так и есть. Это по сути готовое решение, причём очень неплохое. Нам ведь бизнес-задачи нужно решать?
                          • +1
                            У автора отличная библиотека для вебсокетов, но использовав ее для интенсивных нагрузок, периодически (может быть раз в день, без видимой зависимости от внешних факторов) возникал block на пару минут на записи в поток (синхронные сокеты). Хотя все теоретические тонкие моменты были предусмотрены (проверка готовности, проверки полных отправленных данных и тп). На Ratchet-е все ок.
                            Но коментарий не камень в огород, а благодарность за работу — либка хорошо написана и было удобно использовать!
                            • +2

                              После знакомства с https://github.com/centrifugal/centrifugo я для себя этот вопрос закрыл раз и навсегда
                              Спасибо fzambia

                              • 0

                                Аналогично, уже 2 проекта с ним делаем, до этого писали свои поделки на socket-io. Был один проект на Ratchet года 2 назад и как-то что-то не рекомендую больше никому так делать.

                                • 0
                                  Был один проект на Ratchet года 2 назад и как-то что-то не рекомендую больше никому так делать.

                                  А не поделитесь какие именно проблемы? В разработке и (или) эксплуатации?
                                  • 0

                                    В разработке он не так удобен как связка из php + nodejs + socket-io через zeromq какой. На тот момент были какие-то проблемы с реализацией протокола, всех нюансов уже не упомню. Ну и отдельная проблема — найти библиотеки с учетом event loop и т.д. практически невозможно, потому по итогу вышло всеравно так что от основного приложения мы отделили это все через zeromq. А если так — то на кой черт websockts на php непонятно.

                              • +2
                                Когда начинали проект решили попробовать centrifugo, как оказалось этот проект идеально нам подходит. По набору возможностей и эффективности впереди Ratchet и вообще любого web socket сервера что я пробовал. Автор оперативно отвечает на issue и принимает feature request. Спасибо fzambia за плодотворное сотрудничество.
                                • 0
                                  Я в своё время столкнувшесь с задачей реализации чата пошёл несколько дальше в области велосипедо строения чем написание своей библитоки на php. Так как я на тот момент знал не только php и JavaScript но ещё и C++ то я решил проблему работы с вебсокетами путём написания отдельного многопоточного сервера на C++.
                                  В итоге получился проект CppComet

                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.