Pull to refresh

Двунаправленный асинхронный обмен данными в веб-приложениях

Reading time4 min
Views20K
Одной из основных черт современного веба эксперты называют RIA, что часто расшифровывается как тренд, когда веб-приложения по функциональности приближены к настольным приложениям. Тем не менее, это приближение весьма условно. Подавляющее большинство «обогащеных» веб-приложений по-прежнему построены по модели «запрос-ответ». Т.е. события на стороне клиента могут быть отражены на стороне сервера, никак не наоборот. Для того чтобы реализовать такую банальную вещь как чат приходиться прибегать к изощренным уловкам. Спасибо Алексу Расселу (Alex Russell) из Dojo, у нас есть даже имя для подобной техники – Comet.

Согласно 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).

image

Ура, спасибо, все свободны? А вот и нет. В настоящий момент 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.
Tags:
Hubs:
+60
Comments52

Articles