Одной из основных черт современного веба эксперты называют RIA, что часто расшифровывается как тренд, когда веб-приложения по функциональности приближены к настольным приложениям. Тем не менее, это приближение весьма условно. Подавляющее большинство «обогащеных» веб-приложений по-прежнему построены по модели «запрос-ответ». Т.е. события на стороне клиента могут быть отражены на стороне сервера, никак не наоборот. Для того чтобы реализовать такую банальную вещь как чат приходиться прибегать к изощренным уловкам. Спасибо Алексу Расселу (Alex Russell) из Dojo, у нас есть даже имя для подобной техники – Comet.
Согласно cometdaily.com, существует несколько решений для того, чтобы эмулировать двунаправленный обмен данными между клиентом и сервером:
Помимо этого возможно использование Flash объектов или Java-апплетов. И для полноты картины можно упомянуть такую древнюю технику как Forever GIF.
От себя я бы еще добавил пару высокоуровневых решений:
Как бы там ни было, любой из этих подходов в той или иной мере хак, когда хотелось бы использовать нативное решение. Ребята из рабочей группы HTML5, очевидно, хорошо понимают эту ситуацию и потому в стандарт внесен такой метод как Web Sockets. Его описание звучит как панацея: толерантен к фаерволам и роутерам, позволяет кросс-доменную коммуникацию, интегрируется с существующими HTTP балансерами нагрузки, допускает обмен бинарными данными, работает в защищенных соединениях и т.д. При всем при этом, API Web Sockets – очень простой (см. также habrahabr.ru/blogs/webdev/79038).
Ура, спасибо, все свободны? А вот и нет. В настоящий момент Web Sockets поддерживается только в девелоперской версии Chrome (начиная с 4.0.249.0 — www.chromium.org/getting-involved/dev-channel) и обещана поддержка в Firefox 3.7. Что же делать сейчас? Очевидно нужен фасад на клиентской стороне, который при наличии Web Socket использует его «родной» API, при отсутствии – обходное решение. Таким решением мог бы быть Kaazing Websocket Gateway ( kaazing.com/download ), если бы распространялся не за деньги, а по доброте душевной. Можно было бы использовать Orbited ( orbited.org ) совместно с io.js ( github.com/mcarter/js.io ), если вам непременно необходим помимо Web Sockets доступ в amqp, imap, irc, ldap, smtp, ssh, stomp, telnet, xmpp и Python на сервере проксирующий любые коммуникации. Мой выбор: WebSocket.js ( github.com/gimite/web-socket-js ). Крохотная JS библиотека и мост виде Flash-объекта.
Теперь нам понадобится лишь сервер WebSocket и, в нашем случае (бакенд написан на Java), для этого отлично подходит Jetty, начиная с версии 7.0.1 (в настоящий момент ее статус — almost stable, но когда нас это пугало?). Если ваши серверные приложения написаны на php можно попробовать использовать phpwebsocket ( code.google.com/p/phpwebsocket ) или Phpwebsockets ( code.google.com/p/phpwebsockets ). Но на свой страх и риск так как оба решения экспериментальные.
UPDATED: Пример реализации чата на phpDaemon habrahabr.ru/blogs/php/79377
Уверен инсталляция Jetty не вызовет у вас никаких вопросов, но вы можете столкнуться с проблемой в WebSocket.js из-за, так называемой, cross-domain policy от Adobe. Flash-объекту надо разрешить открывать сокет на сервере. Самое надежное решение – разместить микро-сервер на порт 843, отвечающий на запрос политик соответствующим XML, как описано в www.lightsphere.com/dev/articles/flash_socket_policy.html. В статье даже представлен простеший XML-сервер на перле. Впрочем, мне он не очень понравился, и я писал свой сокет-сервер на базе примера из devzone.zend.com/article/1086.
Теперь, когда мы располагаем Web Sockets, мы можем написать веб-приложения, способные мгновенно реагировать на события сервера. Это может быть система оповещений (notificatior) как на Facebook, это могут быть сервисы для взаимодействия пользователей в стиле Google Waves, это могут быть мониторы реального времени (например, пользователи онлайн) или же интеграция со сторонними источниками событий, таких как входящее SMS или событие в настольном приложении. Поскольку мы ожидаем самые разные события, из различных источников, направленные различным клиентам, потребуется надежная система управления потоками сообщений на сервере. Существует простой, но элегантный протокол STOMP ( stomp.codehaus.org ). В API всего несколько команд (SEND, SUBSCRIBE, UNSUBSCRIBE, BEGIN, COMMIT, ABORT, ACK, DISCONNECT) посредством которых общаются STOMP клиенты и STOMP брокеры. В частности в Zend Queue ( framework.zend.com/manual/en/zend.queue.stomp.html ) имеется адаптер STOMP. Брокер сообщений может быть реализован на базе Apache ActiveMQ ( activemq.apache.org ) или же RabbitMQ ( www.rabbitmq.com ).
Впрочем, если вы настроены очень серьезно стоит обратить внимание на более развитый и гибкий ( habrahabr.ru/blogs/webdev/62502 ) протокол AMQP ( www.amqp.org ).
Jetty, будучи контейнером JBOSS, обслуживает Web Sockets. Нам осталось использовать другой контейнер чтобы транслировать AMQP оповещения в Web Sockets. Для это следует установить один из брокеров для AMPQ. ZeroMQ ( www.zeromq.org ) считается самым быстрым. Qpid ( qpid.apache.org/amqp-brokers.html ) достаточно популярен, чего и следует ожидать от проекта Apache.
Согласно cometdaily.com, существует несколько решений для того, чтобы эмулировать двунаправленный обмен данными между клиентом и сервером:
- Long polling – сервер не отвечает сразу на XHR-запрос, а лишь тогда, когда в очередь приходит событие, адресованное данному источнику («вопрошающему»).
- Forever frame – создает iframe, в который сервер постоянно дописывает события по мере их поступлений.
- Script tags – динамически создаваемые JS-блоки, что позволяет кросс-доменные коммуникации.
- ActiveXObject(”htmlfile”) – метод доступный в IE и использующий ActiveX
- JSONRequest object ( www.json.org/JSONRequest.html ) — реализует двух-стороннее соединение, посредством двух одновременных запросов (один на передачу, другой на прием).
Помимо этого возможно использование Flash объектов или Java-апплетов. И для полноты картины можно упомянуть такую древнюю технику как Forever GIF.
От себя я бы еще добавил пару высокоуровневых решений:
- Протокол Bayeux ( svn.cometd.com/trunk/bayeux/bayeux.html Dojo Foundation) — позволяет обмен событиями по схемам: один клиент – много серверов, один сервер – много клиентов. В частности используется в проекте CometD (www.cometd.com).
- Протокол BOSH (http://xmpp.org/extensions/xep-0124.html XMPP standards foundation) – эмулирует двунаправленный поток данных между браузером и сервером, используя два синхронных HTTP-соединения
- Lightstreamer ( www.lightstreamer.com ) – масштабируемый и надежный сервер для «пушинга» данных в «обогащегнное» приложение в реальном масштабе времени.
- APE (Ajax Push Engine) ( www.ape-project.org ) – легковесный open source push-сервер, нашедший поддержку в MooTools, Dojo, jQuery. Подробнее на Хабре ( habrahabr.ru/blogs/webdev/60803).
Как бы там ни было, любой из этих подходов в той или иной мере хак, когда хотелось бы использовать нативное решение. Ребята из рабочей группы HTML5, очевидно, хорошо понимают эту ситуацию и потому в стандарт внесен такой метод как Web Sockets. Его описание звучит как панацея: толерантен к фаерволам и роутерам, позволяет кросс-доменную коммуникацию, интегрируется с существующими HTTP балансерами нагрузки, допускает обмен бинарными данными, работает в защищенных соединениях и т.д. При всем при этом, API Web Sockets – очень простой (см. также habrahabr.ru/blogs/webdev/79038).
Ура, спасибо, все свободны? А вот и нет. В настоящий момент Web Sockets поддерживается только в девелоперской версии Chrome (начиная с 4.0.249.0 — www.chromium.org/getting-involved/dev-channel) и обещана поддержка в Firefox 3.7. Что же делать сейчас? Очевидно нужен фасад на клиентской стороне, который при наличии Web Socket использует его «родной» API, при отсутствии – обходное решение. Таким решением мог бы быть Kaazing Websocket Gateway ( kaazing.com/download ), если бы распространялся не за деньги, а по доброте душевной. Можно было бы использовать Orbited ( orbited.org ) совместно с io.js ( github.com/mcarter/js.io ), если вам непременно необходим помимо Web Sockets доступ в amqp, imap, irc, ldap, smtp, ssh, stomp, telnet, xmpp и Python на сервере проксирующий любые коммуникации. Мой выбор: WebSocket.js ( github.com/gimite/web-socket-js ). Крохотная JS библиотека и мост виде Flash-объекта.
Теперь нам понадобится лишь сервер WebSocket и, в нашем случае (бакенд написан на Java), для этого отлично подходит Jetty, начиная с версии 7.0.1 (в настоящий момент ее статус — almost stable, но когда нас это пугало?). Если ваши серверные приложения написаны на php можно попробовать использовать phpwebsocket ( code.google.com/p/phpwebsocket ) или Phpwebsockets ( code.google.com/p/phpwebsockets ). Но на свой страх и риск так как оба решения экспериментальные.
UPDATED: Пример реализации чата на phpDaemon habrahabr.ru/blogs/php/79377
Уверен инсталляция Jetty не вызовет у вас никаких вопросов, но вы можете столкнуться с проблемой в WebSocket.js из-за, так называемой, cross-domain policy от Adobe. Flash-объекту надо разрешить открывать сокет на сервере. Самое надежное решение – разместить микро-сервер на порт 843, отвечающий на запрос политик соответствующим XML, как описано в www.lightsphere.com/dev/articles/flash_socket_policy.html. В статье даже представлен простеший XML-сервер на перле. Впрочем, мне он не очень понравился, и я писал свой сокет-сервер на базе примера из devzone.zend.com/article/1086.
Теперь, когда мы располагаем Web Sockets, мы можем написать веб-приложения, способные мгновенно реагировать на события сервера. Это может быть система оповещений (notificatior) как на Facebook, это могут быть сервисы для взаимодействия пользователей в стиле Google Waves, это могут быть мониторы реального времени (например, пользователи онлайн) или же интеграция со сторонними источниками событий, таких как входящее SMS или событие в настольном приложении. Поскольку мы ожидаем самые разные события, из различных источников, направленные различным клиентам, потребуется надежная система управления потоками сообщений на сервере. Существует простой, но элегантный протокол STOMP ( stomp.codehaus.org ). В API всего несколько команд (SEND, SUBSCRIBE, UNSUBSCRIBE, BEGIN, COMMIT, ABORT, ACK, DISCONNECT) посредством которых общаются STOMP клиенты и STOMP брокеры. В частности в Zend Queue ( framework.zend.com/manual/en/zend.queue.stomp.html ) имеется адаптер STOMP. Брокер сообщений может быть реализован на базе Apache ActiveMQ ( activemq.apache.org ) или же RabbitMQ ( www.rabbitmq.com ).
Впрочем, если вы настроены очень серьезно стоит обратить внимание на более развитый и гибкий ( habrahabr.ru/blogs/webdev/62502 ) протокол AMQP ( www.amqp.org ).
Jetty, будучи контейнером JBOSS, обслуживает Web Sockets. Нам осталось использовать другой контейнер чтобы транслировать AMQP оповещения в Web Sockets. Для это следует установить один из брокеров для AMPQ. ZeroMQ ( www.zeromq.org ) считается самым быстрым. Qpid ( qpid.apache.org/amqp-brokers.html ) достаточно популярен, чего и следует ожидать от проекта Apache.