Introducing WebSockets - Bringing sockets to the web (Знакомство с WebSockets – сокеты в интернете)

Проблема: низкая задержка при подключении клиента к серверу и сервера к клиенту

Интернет в основном построен на так называемой парадигме запроса/ответа HTTP. Клиент загружает веб-страницу, и ничего не происходит, пока пользователь не перейдет на следующую страницу. Примерно в 2005 году технология AJAX сделала веб-страницы более динамичными. Тем не менее, все HTTP-взаимодействие управлялось клиентом, что требовало взаимодействия с пользователем или периодического опроса для загрузки новых данных с сервера.

Технологии, позволяющие серверу отправлять данные клиенту в тот самый момент, когда он узнает, что доступны новые данные, существуют уже довольно давно. Они могут называться по-разному, например Push или Comet. Один из самых распространенных способов создать иллюзию соединения, инициированного сервером, называется длинным опросом. При использовании длинных опросов клиент открывает HTTP-подключение к серверу, которое остается открытым до отправки ответа. Когда на сервере появляются новые данные, он отправляет ответ. Другие методы включают запросы Flash, XHR multipart и так называемые htmlfiles. Длинные опросы и другие методы работают достаточно хорошо. Вы используете их каждый день в таких приложениях, как чат GMail.

Однако у всех этих обходных путей есть одна общая проблема: они несут в себе накладные расходы HTTP, что делает их непригодными для приложений с низкой задержкой. Например, многопользовательские шутеры от первого лица в браузере или любые другие онлайн-игры с компонентом реального времени.

Introducing WebSocket: Bringing sockets to the web (Знакомство с 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 г. зарегистрировано только одно название подпротокола (soap).

// 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 – расширения. С помощью расширений можно отправлять сжатые, мультиплексированные и другие фреймы. Чтобы узнать, какие расширения принимает сервер, проверьте свойство extensions объекта WebSocket после события open. По состоянию на февраль 2012 г. официальная спецификация расширений ещё не опубликована.

// Determining accepted extensions
console.log(connection.extensions);

Обмен данными между источниками

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

Прокси-серверы

Каждая новая технология приносит с собой новые проблемы. В случае с WebSocket это совместимость с прокси-серверами, которые опосредуют HTTP-соединения в большинстве корпоративных сетей. Протокол WebSocket использует систему обновления HTTP (которая обычно используется для HTTP/SSL), чтобы "обновить" HTTP-соединение до WebSocket-соединения. Некоторые прокси-серверы не поддерживают такой режим и разрывают соединение. Таким образом, даже если клиент использует протокол WebSocket, установить подключение может быть невозможно. Поэтому следующий раздел ещё важнее :)

Начните использовать WebSockets

WebSocket – это новая технология, которая пока не полностью поддерживается всеми браузерами. Однако вы можете использовать WebSocket уже сейчас с библиотеками, которые используют один из упомянутых выше резервных вариантов, когда WebSocket недоступен. Очень популярной библиотекой в этой области стала socket.io, которая поставляется с клиентской и серверной реализацией протокола и включает резервные варианты (по состоянию на февраль 2012 года socket.io пока не поддерживает обмен двоичными сообщениями). Существуют также коммерческие решения, такие как PusherApp, которые можно легко интегрировать в любую веб-среду, предоставив HTTP API для отправки сообщений WebSocket клиентам. Из-за дополнительного HTTP-запроса всегда будут дополнительные накладные расходы по сравнению с чистым WebSocket.

Сторона сервера.

Использование WebSocket создает совершенно новую модель использования для серверных приложений. Традиционные стеки серверов, такие как LAMP, разработаны для цикла HTTP-запросов и ответов, поэтому они часто не справляются с большим количеством открытых подключений WebSocket. Чтобы поддерживать большое количество одновременных подключений, требуется архитектура, которая обеспечивает высокую параллельность при низких затратах на производительность. Такие архитектуры обычно разрабатываются на основе потоков или так называемого неблокирующего ввода-вывода.

Реализация на стороне сервера

Версии протоколов

Протокол передачи данных (рукопожатие и передача данных между клиентом и сервером) для WebSocket теперь соответствует стандарту RFC6455. Последние версии Chrome и Chrome для Android полностью совместимы с RFC6455, включая двоичные сообщения. Кроме того, Firefox будет совместим с версией 11, а Internet Explorer – с версией 10. Вы можете использовать более старые версии протокола, но это не рекомендуется, поскольку они уязвимы. Если на вашем сервере реализованы более ранние версии протокола WebSocket, рекомендуем обновить его до последней версии.

Примеры использования

Используйте WebSocket, когда вам нужно по-настоящему низкое время задержки и связь между клиентом и сервером практически в реальном времени. Возможно, вам придется пересмотреть подход к созданию серверных приложений и уделить больше внимания таким технологиям, как очереди событий. Вот несколько примеров использования:

  • Многопользовательские онлайн-игры
  • Приложения Chat
  • Бегущая строка со спортивными новостями
  • Обновление социальных лент в реальном времени

Деморолики

Ссылки