Работаем с phpDaemon

Серверы FastCGI, HTTP, CGI, FlashPolicy, Telnet, клиенты mysql, memcached, mongodb — вот неполный список функционала, реализованного в этом демоне, созданном российским программистом Василием Зориным.

Впрочем, нас сейчас интересуют только WebSocket, и это phpDae-mon тоже умеет. Процесс установки фрэйворка имеет свои нюансы, поэтому остановимся на нем чуть подробней.

PhpDaemon требует для своей работы библиотеку libevent — это кроссплатформенная библиотека для асинхронной работы с сетью, предоставляющая механизм, использующий функции обратного вызова. В репозитории Pecl имеется расширение для работы с libevent посредством php, но, чтобы его собрать, нам, возможно, понадобится утилита phpize из пакета php-devel. Впрочем, это обстоятельство нас не должно останавливать.

Действуем:

$ sudo aptitude install php5-dev

Это естественно для пользователей Debian или Ubuntu. Если у вас Red Hat, Fedora или CentOS, команда будет:

$ sudo yum install php53-devel

Если вы используете Windows… ну, в общем, лучше поставить виртуальную машину.

Далее устанавливаем расширение libevent (сама библиотека должна быть уже установлена):

Pecl install libevent

После установки необходимо в php. ini прописать следующую строчку, если ее нет в наличии:

Extension=libevent. so

(Нам важно это сделать для cli-интерпретатора, то есть путь к конфигурационному файлу будет вида: /etc/php5/cli/php. ini.)

И наконец, устанавливаем PhpDaemon:

Cd /usr/local

Git clone git://github. com/kakserpom/phpdaemon. git chmod +x phpdaemon/bin/phpd

Ln — s /usr/local/phpdaemon/bin/phpd /usr/bin/phpd

Для DEBIAN-like:

Ln — s /usr/bin/phpd /etc/init. d/phpd update-rc. d phpd defaults

Запускаем:

phpd start

Хотя с запуском мы наверняка поторопились, и, возможно, в консоль вывалятся несколько ошибок. Это не беда, сейчас все исправим. Прежде всего редактируем файл конфигурации — phpdaemon/conf/ phpd. conf. Он должен будет выглядеть примерно так:

## Config file

User root; group root;

Max-workers20; min-workers20;

Max-requests 1m;

Max-idle 0;

Example { enable 1: privileged;

}

ServerStatus { enable 1; privileged;

}

Log-errors 1;

HTTP {

Privileged; enable 1; listen-port 8080:

}

Server { privileged;

}

ExampleWebSocket { enable  1;

Path  /usr/local/lib/phpdaemon/applications/ExampleWebSocket. php:

Listenport 8047; user  www;

Group  www;

}

WebSocketOverCOMET { enable  1;

}

# other applications…

Path = /usr/local/lib/phpdaemon/AppResolver. php

Include conf. d/*.conf:

Я тут не буду останавливаться на деталях настройки среды phpdaemon, весь конфигурационный файл я привожу только для того, чтобы его можно было без изменений использовать в своих опытах читателю. Наиболее важны конструкции Server и Example-WebSocket. Первая из них выключает веб-сокеты, вторая регистрирует тестовое приложение. Параметр path указывает на его физическое размещение.

Очень важным параметром конфигурации является строчка

Path = /usr/local/lib/phpdaemon/AppResolver. php,

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

Практически на этом настройка phpdaemon завершена. По адресу, указанному нами в phpd. conf (hpdaemon/applications/), разместим файл ExampleWebSocket. php из каталога примеров phpdaemon (hpdaemon/applications/app-examples). Особо останавливаться на его содержании пока не имеет смысла, скажем только, что вся функциональность этого сервиса заключается в отправке слова «pong» в ответ на поступивший внешний запрос «ping».

Теперь мы озаботимся клиентской частью. В дистрибутив phpdae-mon входит хороший инструментарий для тестирования технологий. В папке phpdaemon/clientside-connectors/websocket/ находятся набор js-файлов и пример html-страницы, работающей с веб-сокетами, требующей минимальной настройки (рис. 105). Причем для браузеров, не поддерживающих WebSocket, выполнена эмуляция процесса с использованием технологий COMET/Long Pooling и даже flash. Но нам это не очень интересно, не будем искать легких путей и напишем свой WebSocket-клиент:

}

Function messageEvent(msg){ alert(msg. data):

}

Function closeEvent(){ alert("close");

}

</script>

<button onclick="create();">Create WebSocket</button> <button onclick="sendEvent(‘ping’);">Send ping</button> <button onclick="WS. close();">Close WebSocket</button>

</body>

</html>

Рис. 105. Работаем с WebSockets

Тут мы видим три кнопки, первая из которых создает сокет (и, соответственно, устанавливает соединение), вызывая функцию WebSocketConnection, которая, в свою очередь, создает объект WebSocket(), параметром конструктора которого является url нашего WebSocket-приложения. Второй, необязательный параметр — протокол, их может быть несколько.

После установки соединения (нас известит об этом соответствующий alert) можно пользоваться клавишей Send ping, посылающей сообщение в сокет. При получении сообщения со стороны сервера срабатывает событие onmessage, в результате которого в нашем случае будет выведено сообщение с ответом сервера (рис. 106). Клавиша Close WebSocket закрывает сокет — поле этого взаимодействие

С сервером прекращается. Данные посылаются и принимаются в виде строк, но ничто не мешает обмениваться и JSON-объектами:

Function sendText() { var msg ={

Type: "message", text: "Hello WebSockets.!", id: clientID, date: Date. now()

};

WS. send(JSON. stringify(msg));

Pong

— Prevent this page from creating additional dia

Ogs.

OK

I

Рис. 106. Ответ через WebSocket

Словом, все, как в обычном клиент-серверном веб-взаимодействии. Как выглядит серверная часть, нас, строго говоря, не должно интересовать, но давайте взглянем на ее реализацию просто для общего развития.

В файле phpdaemon/application/ExsampleWebSocket. php описаны два класса (автор кода — Zorin Vasily <kak. serpom. po. yaitsam@gmail. com>):

* Called when new frame received.

* @param string Frame’s contents.

* @param integer Frame’s type.

* @return void */

Public function onFrame($data, $type) { if ($data === ‘ping’) {

$this->client->sendFrame(‘ pong’, WebSocketSERVER::STRING, function($client) {

Daemon::log(‘ExampleWebSocket: ‘pong’ received by client.’); }

):

}

}

}

Первый из них вызывается при создании веб-сокета и возвращает объект нового сеанса работы с ним. Второй является реализацией этого сеанса и содержит метод onFrame, принимающий сообщение и отсылающий ответ.

Что мы можем теперь получить, исходя из имеющегося арсенала средств? Да практически все, препятствий в виде HTTP-протокола больше нет. Вернее, сам HTTP никуда не делся, но особенности его архитектуры — больше не помеха. Помеха в другом — слабой пока поддержке технологии как в браузерах, так и на веб-серверах. Но, я думаю, никто не сомневается, что это все временно. Гораздо более существенным выглядит другой, «врожденный» недостаток технологии — отсутствие ограничения срока жизни запроса. Дело в том, что WebSockets — это TCP-сокет, а не HTTP-запрос, он не имеет природы «запрос/ответ на запрос», и это, помимо преимуществ, имеет и обратную сторону — неудобство работы сервисов, ограниченных одним запросом. Ну что же, серебряной пули не существует, просто разработчику надо всегда иметь в виду такое поведение при взаимодействии с сервером.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *