Представляем веб-сокеты: использование сокетов в Интернете

HTML5 Rocks

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

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

Технологии, позволяющие серверу отправлять клиенту новые данные в момент их появления, существуют довольно давно. Они известны как Push или Comet. Один из распространенных способов создания иллюзии соединения, инициируемого сервером, – это так называемый метод длинного опроса. Его суть в том, что клиент создает подключение к HTTP-серверу и оно не закрывается до отправки ответа. Если на сервере действительно есть обновленные данные, он отправляет ответ (в других технологиях для этого используются Flash, multipart-запросы XHR и особые HTML-файлы). Технология длинного опроса, как и другие подобные приемы, прекрасно работает. Вы пользуетесь ими каждый день, например, в чате Gmail.

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

Знакомство с протоколом WebSocket: использование веб-сокетов в Интернете

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

Начало работы

Чтобы создать подключение WebSocket, можно вызвать соответствующий конструктор.

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);

Обратите внимание на ws:: это новая схема URL для веб-сокетов. Для создания безопасных веб-сокетов также используется схема wss:, аналогично протоколу 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('сообщение') объекта подключения. Ранее она принимала только строки, однако в последней версии спецификации поддерживаются и двоичные сообщения. Для отправки таких данных используются объекты 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 появилась совсем недавно и не полностью реализована во всех браузерах. Несмотря на это, можно воспользоваться упомянутыми выше библиотеками для реализации обратной совместимости в случаях, когда протокол WebSocket не поддерживается. Одной из самых популярных библиотек является socket.io, в которой возможности протокола реализованы как на стороне сервера, так и на стороне клиента, а также обеспечена обратная совместимость (по состоянию на февраль 2012 г. socket.io не поддерживает обмен двоичными сообщениями). Существуют и коммерческие решения, например PusherApp, который легко интегрируется в любые веб-приложения и реализуют отправку сообщений WebSocket клиентам с помощью API на базе HTTP. Использование HTTP-запросов неизменно повышает потребление ресурсов в сравнении со стандартной технологией WebSocket.

На стороне сервера

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

Серверные реализации

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

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

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

Протокол WebSocket позволяет приблизить время реакции при обмене данными между клиентом и сервером к параметрам подключения в реальном времени. Учтите, что использование этого протокола может потребовать изменения подхода к реализации серверных приложений и применения других технологий, например очереди событий. Вот несколько возможных сфер применения.

  • Многопользовательские сетевые игры
  • Чаты
  • Бегущая строка
  • Ленты социальных сетей, обновляемые в реальном времени

Демонстрационные примеры

Полезные ссылки

Comments

0