Проблема: соединения клиент-сервер и сервер-клиент с низкой задержкой.
Сеть во многом построена на так называемой парадигме запроса/ответа HTTP. Клиент загружает веб-страницу, а затем ничего не происходит, пока пользователь не нажмет на следующую страницу. Примерно в 2005 году AJAX начал делать Интернет более динамичным. Тем не менее, вся HTTP-связь управлялась клиентом, что требовало взаимодействия с пользователем или периодического опроса для загрузки новых данных с сервера.
Технологии, которые позволяют серверу отправлять данные клиенту в тот самый момент, когда он узнает о доступности новых данных, существуют уже довольно давно. Они носят такие имена, как «Пуш» или «Комета» . Один из наиболее распространенных приемов создания иллюзии соединения, инициированного сервером, называется длинным опросом. При длительном опросе клиент открывает HTTP-соединение с сервером, которое остается открытым до отправки ответа. Всякий раз, когда у сервера действительно появляются новые данные, он отправляет ответ (другие методы включают Flash , многочастные запросы XHR и так называемые htmlfiles ). Длинный опрос и другие методы работают достаточно хорошо. Вы используете их каждый день в таких приложениях, как чат GMail.
Однако все эти обходные пути имеют одну общую проблему: они несут накладные расходы HTTP, что не делает их подходящими для приложений с низкой задержкой. Подумайте о многопользовательских шутерах от первого лица в браузере или любой другой онлайн-игре с компонентом реального времени.
Представляем WebSocket: перенос сокетов в Интернет
Спецификация WebSocket определяет API, устанавливающий «сокетные» соединения между веб-браузером и сервером. Проще говоря: между клиентом и сервером существует постоянное соединение, и обе стороны могут начать отправку данных в любое время.
Начиная
Вы открываете соединение WebSocket, просто вызывая конструктор WebSocket:
var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
Обратите внимание на ws:
. Это новая схема URL-адресов для соединений WebSocket. Существует также wss:
для безопасного соединения WebSocket, так же, как https:
используется для безопасных HTTP-соединений.
Присоединение некоторых обработчиков событий непосредственно к соединению позволяет узнать, когда соединение открыто, получены входящие сообщения или возникла ошибка.
Второй аргумент принимает необязательные подпротоколы. Это может быть строка или массив строк. Каждая строка должна представлять имя субпротокола, и сервер принимает только один из переданных субпротоколов в массиве. Принятый подпротокол можно определить, обратившись к свойству protocol
объекта WebSocket.
Имена подпротоколов должны быть одним из зарегистрированных имен подпротоколов в реестре IANA . В настоящее время по состоянию на февраль 2012 года зарегистрировано только одно название подпротокола (мыло).
// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
Общение с сервером
Как только у нас появится соединение с сервером (когда запускается событие open
), мы можем начать отправлять данные на сервер, используя метод send('your message')
объекта соединения. Раньше он поддерживал только строки, но в последней спецификации теперь может отправлять и двоичные сообщения. Для отправки двоичных данных вы можете использовать объект Blob
или ArrayBuffer
.
// Sending String
connection.send('your message');
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
connection.send(binary.buffer);
// Sending file as Blob
var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);
Точно так же сервер может отправлять нам сообщения в любое время. Всякий раз, когда это происходит, срабатывает обратный вызов onmessage
. Обратный вызов получает объект события, а фактическое сообщение доступно через свойство data
.
WebSocket также может получать двоичные сообщения в последней спецификации. Бинарные кадры можно получать в формате Blob
или ArrayBuffer
. Чтобы указать формат полученного двоичного файла, установите для свойстваbinaryType объекта WebSocket значение «blob» или «arraybuffer». Формат по умолчанию — «BLOB». (Вам не нужно выравнивать параметрbinaryType при отправке.)
// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
console.log(e.data.byteLength); // ArrayBuffer object if binary
};
Еще одна новая добавленная функция WebSocket — расширения. Используя расширения, можно будет отправлять кадры сжатыми , мультиплексированными и т. д. Вы можете найти расширения, принятые сервером, исследуя свойство расширений объекта WebSocket после события open. По состоянию на февраль 2012 года официально опубликованной спецификации расширений пока нет.
// Determining accepted extensions
console.log(connection.extensions);
Междоменная коммуникация
Будучи современным протоколом, перекрестная связь встроена прямо в WebSocket. Хотя вам все равно следует общаться только с клиентами и серверами, которым вы доверяете, WebSocket обеспечивает связь между сторонами в любом домене. Сервер решает, сделать ли свою службу доступной для всех клиентов или только для тех, кто находится в наборе четко определенных доменов.
Прокси-серверы
Каждая новая технология сопряжена с новым набором проблем. В случае WebSocket это совместимость с прокси-серверами, которые обеспечивают HTTP-соединения в большинстве сетей компаний. Протокол WebSocket использует систему обновления HTTP (которая обычно используется для HTTP/SSL) для «обновления» HTTP-соединения до соединения WebSocket. Некоторым прокси-серверам это не нравится, и они разрывают соединение. Таким образом, даже если данный клиент использует протокол WebSocket, установить соединение может быть невозможно. Это делает следующий раздел еще более важным :)
Используйте WebSockets сегодня
WebSocket — еще молодая технология, которая не полностью реализована во всех браузерах. Однако сегодня вы можете использовать WebSocket с библиотеками, которые используют один из упомянутых выше резервных вариантов, когда WebSocket недоступен. Библиотека, которая стала очень популярной в этой области, — этоocket.io , которая поставляется с клиентской и серверной реализацией протокола и включает резервные варианты (socket.io еще не поддерживает обмен двоичными сообщениями по состоянию на февраль 2012 года). Существуют также коммерческие решения, такие как PusherApp , которые можно легко интегрировать в любую веб-среду, предоставляя HTTP API для отправки сообщений WebSocket клиентам. Из-за дополнительного HTTP-запроса всегда будут дополнительные накладные расходы по сравнению с чистым WebSocket.
Серверная часть
Использование WebSocket создает совершенно новый шаблон использования серверных приложений. Хотя традиционные серверные стеки, такие как LAMP, разработаны с учетом цикла HTTP-запрос/ответ, они часто плохо справляются с большим количеством открытых соединений WebSocket. Для одновременного поддержания большого количества открытых соединений требуется архитектура, обеспечивающая высокий уровень параллелизма при низких затратах на производительность. Такие архитектуры обычно разрабатываются с использованием многопоточности или так называемого неблокирующего ввода-вывода.
Реализации на стороне сервера
- Node.js
- Ява
- Руби
- Питон
- Эрланг
- С++
- .СЕТЬ
Версии протокола
Проводной протокол (рукопожатие и передача данных между клиентом и сервером) для WebSocket теперь называется RFC6455 . Последние версии Chrome и Chrome для Android полностью совместимы с RFC6455, включая обмен двоичными сообщениями. Кроме того, Firefox будет совместим с версией 11, а Internet Explorer — с версией 10. Вы по-прежнему можете использовать более старые версии протокола, но это не рекомендуется, поскольку известно, что они уязвимы. Если у вас есть реализации сервера для более старых версий протокола WebSocket, мы рекомендуем вам обновить его до последней версии.
Варианты использования
Используйте WebSocket всякий раз, когда вам нужно соединение между клиентом и сервером с действительно низкой задержкой и практически в реальном времени. Имейте в виду, что это может потребовать переосмысления того, как вы создаете серверные приложения, с новым акцентом на таких технологиях, как очереди событий. Некоторые примеры использования:
- Многопользовательские онлайн-игры
- Чат-приложения
- Живой спортивный тикер
- Обновление социальных потоков в реальном времени
Демо
- Плинк
- Рисуй со мной
- Пикселатр
- Пунктирный
- Массовый многопользовательский онлайн-кроссворд
- Ping-сервер (используется в примерах выше)
- Пример HTML5демоверсии