Случаются в жизни огорчения — хотел сделать одно, получилось иное. К примеру, протокол, написанный для навигации между документами, используется как файловый сервер. Или делал ты протокол поверх сети Интернет, а теперь его называют «интернет». В общем-то так и произошло с HTTP — «протоколом передачи гипертекста».
Теперь практически всё реализуется с его поддержкой, чтобы «быть в интырнете». Не предусмотрены протоколом сеансы — добавляем cookie и т.д. Потом, когда увлекаемся извращёнными извращениями — появляются различные Semantic URL, REST, SEO опять же бьёт по рукам тех, кто увлёкся CSS и превратил HTML в span через div. Всё, чтобы слегка сбить спесь и вернуть в родное русло.
Но есть (на данный момент) уж совсем чужеродная хотелка — как сделать так, чтобы не клиент говорил, что ему надо, а сервер. Суть HTTP — клиент спросил документ — мы его отдали. Всё.
А теперь небольшой финт ушами — мы говорим, что документ — структура супер-динамическая и меняется даже во время «ответа». Поэтому ответ сервера на запрос должен уметь сам определять, когда он совершится.
Иными словами мы переходим к серверам, которые шлют запросы подключённым клиентам.
Подход, надо сразу сказать, инородный. Значит мы имеем удовольствие насладиться новыми элегантными костылями!
Ajax по timeout
Самым простым способом получать изменения в «документе» — периодически спрашивать сервер «что-то произошло?». Из плюсов: простота. В минусах: куча запросов будут лишними, а ответ с сервера будет не «real time», а по запросу. Когда-то ещё любили ставить meta refresh…
Comet
Более изощрённый метод — так называемый «long-polling«. Иными словами, мы делаем вид, что всё также забираем с сервера документ, но ждём, пока этот документ не «сгенерируется» — пока не произойдёт на сервере событие, по которому отправится нам информация. Обычно, клиент в таком состоянии висит минут 5, по прошествии которых сервер говорит, что «ничего не произошло». Ответ получен — переподключаюсь! Либо что-то таки происходит — клиент сразу получает желаемое… и переподключается.
Всё в ту же кучу — chunk response — отвечаем «не целым документом», а его «частями» (streaming). Мы можем не пересоздавать запрос каждый раз — просто каждый ответ сервера будет частью некоего «документа».
К примеру, если мы делаем real-time уведомления для пользователей, то сервер будет слать на клиент «части документа» уведомлений. А клиент сможет их получать сразу, без ожидания.
WebSocket
Даёт всё ровно то, что есть в названии. Это аналог TCP-сокетов (транспортного уровня) такие же каналы данных, по которым можно гонять как бинари, так и UTF-8 строки. Особых ограничений нет — просто после запроса к серверу клиент (браузер) не закрывает соединение. В результате: когда хочешь написать — тогда и пишешь, написали тебе — получай данные. По сути — Интернет внутри HTTP.
Comet vs WebSocket
Для небольших сервисов разницы особой нет. Разве что стоит держать «нос по ветру», ибо фичи и библиотеки появляются там, где есть интерес:
Мнение ребят из гугла:
«Reducing kilobytes of data to 2 bytes…and reducing latency from 150ms to 50ms is far more than marginal. In fact, these two factors alone are enough to make Web Sockets seriously interesting to Google.»
Суть: в комете и запросов больше, сами запросы больше (за счёт тех же хедеров HTTP). Да и отклик ниже.
Небольшой надуманный тест производительности:
- Случай A — 1000 клиентов получают 1 сообщение в секунду. Сообщение 2 байта.
- Случай B — 10k клиентов.
- Случай C — 100k.
По количеству гоняемых данных получается ↑. Это про «накладные расходы» и размер запросов.
Утверждение про время отклика также легко описывается схемкой:
По сложности разработки backend схожи: если у нас был обычный web-сервер, который отдавал странички и отвечал на xhr, то теперь нам нужно чтобы он или иной сервер держал коннекты Comet или WebSocket. Тут, скорее всего подойдёт что-нибудь событийно-ориентированное или с потоками уровня приложения. А ля Mojolicious, Twisted|Tornado|gevent, node.js и т.д. Ибо нужно сервить множество клиентов одновременно, но «единица работы» на коннект мала.
Для frontend напилена куча библиотек, а для WebSocket поддержка прямо «из коробки». При чём Comet реализаций (и подходов) несколько, а для WebSocket есть RFC, по которому работает изкоробочная реализация. Плюс всякие обёртки.
Кто поддерживает WebSoket
IE > 9, FireFox, Chrome, Safari, Opera, iOS Safari, Android Browser > 4.3.
Opera Mini не поддерживает.
По рейтингу can i use на данный момент это 86.49%.
Есть поддержка «из коробки» в nginx (с 1.3.13 19.02.2013). Это позволит использовать один порт несколькими вебсокет-серверами. Более того, можно держать HTTP и WS на одном порту. Можно также ограничивать количество соединений с одного IP и прочие радости.
P.S. Эта заметка писалась впопыхах. Основная цель её — собрать различные графики и убедить «работу» в том, что Comet отмирает, а WebSocket — настоящее и ближайшее будущее. Его и стоит использовать.