Поднимаем WebSocket сервер

    Многие уже наслышаны о революции в расширении HTTP протокола — внедрении технологии WebSocket разработчиками Google Chromium. В данной статье речь пойдет о том, как приручить данного зверя — установке и настройке WebSocket сервера на асинхронном фреймворке phpDaemon.

    Для установки нам потребуется PHP5 CLI >= 5.3 с поддержкой pcntl, shmop и sockets.

    1. Загрузка


    Получаем последнюю версию phpDaemon из репозитория
    $ svn checkout http://phpdaemon.googlecode.com/svn/trunk $path/

    Учтите, что $path должно быть заменено на путь, куда устанавливается phpDaemon

    2. Установка


    Устанавливаем права запуска
    $ chmod +x $path/bin/phpdaemon

    Устанавливаем библиотеку libevent
    $ pecl install libevent

    Привязываем демона к команде phpd
    $ ln -s $path/bin/phpdaemon /usr/bin/phpd


    3. Настройка


    Настраиваем файл $path/conf/phpdaemon.conf.php
    Copy Source | Copy HTML
    1. <?php
    2. // Включаем отображение ошибок
    3. error_reporting(E_ALL);
    4. ini_set('display_errors','1');
    5.  
    6. return array(
    7.     'mod-websocketserver-enable' => 1, // Включаем веб-сокет сервер
    8.     'mod-websocketserver-listen' => 'tcp://0.0.0.0', // Слушаем все IP
    9.     'mod-websocketserver-listenport' => 8047, // Вешаем на отличный от 80, чтобы не конфликтовать с другими веб-серверами
    10.     'max-requests' => 1000, // Максимальное количество запросов
    11.     'max-idle' =>  0, // Максимальное время простоя
    12.     'user' => 'www', // Пользователь
    13.     'group' => 'www', // и группа под которыми запускается демон
    14.     'min-spare-workers' => 5,
    15.     'max-spare-workers' => 20,
    16.     'start-workers' => 1,
    17.     'max-workers' => 50,
    18.     'min-workers' => 1,
    19.     'path' => dirname(__FILE__).'/appResolver.php'
    20. );
    21.  
    22. ?>

    Создаем пример обработчика веб-сокет запросов:

    $path/applications/WebSoketWorker.php
    Copy Source | Copy HTML
    1. <?php
    2. return new WebSocketWorker;
    3. /**<br/> * WebSocket Обработчик<br/> *<br/> */
    4. class WebSocketWorker extends AppInstance {
    5.     /**<br/>     * WebSocket Сервер<br/>     * @var WebSocketServer<br/>     */
    6.     public $ws;
    7.     /**<br/>     * Инициализация обработчика<br/>     */
    8.     public function onReady() {
    9.         $this->ws = Daemon::$appResolver->getInstanceByAppName('WebSocketServer');
    10.         if ($this->ws) {
    11.             $this->ws->routes['myRoute'] = array($this,'openSession');
    12.         }
    13.     }
    14.     /**<br/>     * Открытие новой сессии<br/>     * @param $client<br/>     */
    15.     public function openSession($client) {
    16.         return new WebSocketWorkerSession($client);
    17.     }
    18.  
    19. }
    20. /**<br/> * Websocket Сессия<br/> *<br/> */
    21. class WebSocketWorkerSession {
    22.     public $client;
    23.     /**<br/>     * Инициализация<br/>     * @param $client<br/>     */
    24.     public function __construct($client) {
    25.         Daemon::log('connected');
    26.         $this->client = $client;
    27.     }
    28.     /**<br/>     * Получение сообщения<br/>     * @param $data - тело сообщения<br/>     * @param $type - тип сообщения<br/>     */
    29.     public function onFrame($data,$type) {
    30.         Daemon::log($data);
    31.         if ($data === 'ping') {
    32.             $this->client->sendFrame('pong');
    33.         }
    34.     }
    35.     /**<br/>     * Закрытие сессии<br/>     */
    36.      public function onFinish() {
    37.  
    38.      }
    39. }
    40. ?>


    Вуаля! Наш вебсокет сервер установлен!

    4. Тестирование


    Для тестирования создадим файл с следующим содержанием:

    Copy Source | Copy HTML
    1. <script type="text/javascript">
    2. <!--
    3. if ("WebSocket" in window) {
    4.       var ws = new WebSocket("ws://127.0.0.1:8047/myRoute");
    5.       ws.onopen = function() {
    6.             // Web Socket подключён. Вы можете отправить данные с помощью метода send().
    7.             ws.send("ping");
    8.     };
    9.     //каждый раз, когда браузер получает какие-то данные через веб-сокет
    10.     ws.onmessage = function (evt) {
    11.         alert('Получили сообщение: ' + evt.data );
    12.     };
    13.     ws.onclose = function() {
    14.         // websocket закрыт. 
    15.     };
    16. } else {
    17.     // для браузеров не поддерживающих WebSocket.
    18.     alert('Ваш браузер не поддерживает вебсокеты');
    19. }
    20. //-->
    21. </script>


    В случае успешного подключение вы должны получить сообщение «pong».

    Для поддержки в отличных от Chrome браузерах используйте библиотеку web-socket-js, которая эмулирет веб-сокеты с помощью флеша.
    Share post

    Similar posts

    Comments 21

    • UFO just landed and posted this here
      0
      Эх, всё равно — проблема. Пока остальные браузеры не реализуют, использовать в продакшене — маловероятно.
      А у флеша — нестабильность, проблемы с проксями и файрволами.
        0
        Уже сейчас можно внедрять в RIA, где людей можно насильно пересадить на Chrome
        0
        Под убунтой не могу libevent поставить
          +1
          для установки libevent нужен php-dev, он есть у тебя?
            0
            checking for libevent headers in default path… not found
            configure: error: Cannot find libevent headers
            ERROR: `/tmp/pear/temp/libevent/configure --with-libevent' failed
            вот что пишет…
              0
              Для решения данной проблемы необходимо удалить старый libevent ( т.к. необходим Libevent version >= 1.4.3 )

              Copy Source | Copy HTML
              1. apt-get remove --purge libevent1


              Скачиваем новый и устанавливаем

              Copy Source | Copy HTML
              1. ./configure
              2. make && make install


              Затем уже устанавливаем расширение libevent для php

              Copy Source | Copy HTML
              1. pecl install channel://pecl.php.net/libevent-0.0.2 


                0
                У меня в убунту 10.10 пакет php-fpm зависит от libevent. При сносе libevent сносится php-fpm. Придется php компилировать вручную?
          0
          Хороший пост, думаю имеет смысл пролинковать в ней habrahabr.ru/blogs/php/79377/
            0
            Добавил
            0
            > Настраиваем файл $path/conf/phpdaemon.conf.php…
            Пожалуйста, не надо дезинформировать общественность!
            Не надо трогать appResolver вообще!
              0
              А для чего подгружать кучу других модулей если нужны только вебсокеты? (см. титул статьи)
              0
              Здравствуйте, уважаемый автор!

              Вот эта строчка в коде
                0
                if ($this->ws) {
                $this->ws->routes = array(
                'myRoute' => array($this,'openSession') // route
                );
                }
                Едва не наделала у меня в голове перелом мозга. Причина в том, что автор функционала задумал это вот в таком виде: $this->ws->routes['myRoute'] = array($this,'openSession'); Это и есть в коробочном примере. Если приложение оставить так как у вас, то ни одно аналогичное приложение более работать не будет.
                  0
                  да, я как то и не обратил на это внимание… т.к в своем проекте я использовал только модуль вебсокетов (собственно и статья об их использовании )
                  надо поправить, спасибо
                    0
                    И лучше убрать в самом начале пункта 3, где описывается appDefaults, который трогать не надо вообще. А то население путается :)
                0
                Для версии 0.6 неактуальны конфиги и размещение класса в папке application

                Only users with full accounts can post comments. Log in, please.