Глубокое погружение в WebSockets

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

Это было требованием для приложений с малой задержкой, таких как:

Многопользовательские онлайн-игры;

Чат-приложения;

Обновление социальных лент в реальном времени;

Табло спортивных результатов, спортивные тикеры и т.д.

Решением стали WebSockets. С из широким распространением появилось множество библиотек, упрощающих приложения. Следовательно, многие из нас начали использовать эту технологию, не зная внутреннего устройства, что приводило к неэффективности.

Поэтому в данной статье я попытаюсь охватить основные атрибуты WebSockets, чтобы уменьшить эти пробелы.

Архитектура WebSockets

По своей сути WebSockets определяет API, который устанавливает соединение сокета между клиентом и сервером. Это позволяет веб-браузеру и серверу отправлять данные в любом направлении. Кроме того, он также имеет несколько оптимизаций по сравнению с HTTP, что делает его лучше для связи в реальном времени.

Связь в реальном времени

С помощью HTTP-запросов браузер отправляет файлы cookie и другие заголовки, используя несколько сотен байтов, увеличивая накладные расходы на связь в реальном времени.

Однако с WebSockets последующие сообщения имеют небольшой размер и всего 6 байт служебных данных (2 для заголовка и 4 для значения маски).

Таким образом, WebSockets лучше подходят для передачи данных в реальном времени и особенно для приложений с малой задержкой, поскольку затраты меньше.

Подключение через WebSocket

Открыть соединение WebSocket несложно. Если вам нужно указать подпротоколы, это также можно сделать с помощью второго параметра.

// Create a new WebSocket
let socketConnection = new WebSocket('ws://websocket.mysite.com'); // Create a new WebSocket with subprotocols
let socketConnection = new WebSocket('ws://websocket.mysite.com', ['soap', 'xmpp']);

После создания сокетного соединения вы можете прикрепить к нему обработчики событий, что позволит вам узнать, когда соединение открыто, когда оно получает сообщения и когда возникает ошибка.

// When the connection is open, some data is sent to the server
socketConnection.onopen = function () { connection.send('Hello, the socket connection is open!'); // Send a message to the server
}; // Log errors
socketConnection.onerror = function (error) { console.log('WebSocket Error ' + error);
}; // Log messages from the server
socketConnection.onmessage = function (e) { console.log('Server: ' + e.data);
};

После установления соединения, событие onopen будет запущено в экземпляре WebSocket. И на этом действие завершено. С этого момента любая из сторон может отправлять данные в любое время. Когда WebSocket получает данные на стороне клиента, запускается событие onmessage. Событие onerror может быть использовано для обработки ошибок.

Вы можете спросить, что в этом нового? Разве мы не всегда так поступаем, создавая соединение и прослушивая сообщения?

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

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

Распространенная проблема при работе с WebSockets — это разорванные соединения. Это происходит, когда клиент или сервер не отвечает. Чтобы избежать каких-либо проблем, связанных с этим, вы должны реализовать механизм для корректного закрытия соединения. Особенно если срок службы соединения WebSocket длительный, для обеспечения бесперебойной системы связи необходимо внедрять метод обновления соединений (закрывать и снова открывать соединения).

Масштабирование соединений

Поскольку для WebSockets требуется высокая доступность из-за постоянных подключений, сервер должен быть масштабируемым, чтобы при необходимости удовлетворять высокий спрос. Однако после открытия ws соединения, большую часть времени оно будет бездействовать.

Следовательно, вы можете задаться вопросом, как нам масштабировать серверную часть Websocket?

Масштабирование серверной части WebSocket — сложная задача, для которой потребуется постоянное хранилище (также известное как объединительная плата) для отслеживания подключений и доставленных сообщений, если какой-либо узел сервера выходит из строя.

Кроме того, было бы лучше реализовать стратегию горизонтального масштабирования с учетом количества открытых подключений.

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

Шаблоны передачи данных

При передаче данных через веб-сокеты можно учитывать разные закономерности. Вы можете либо передать сообщение напрямую через WebSockets, либо отправить клиенту уведомление о доступности сообщения.

WebSockets для отправки уведомлений для веб-приложений

Отправка уведомлений в приложении — распространенный вариант использования WebSockets. Соединение WebSocket используется только для предупреждения браузера о наличии нового сообщения.

Как только пользователь получает уведомление и посещает страницу уведомлений, приложение может отправить HTTP-запрос для получения содержимого сообщения.

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

Использование WebSockets для передачи данных в реальном времени

Для многопользовательских игр в реальном времени или приложений чата данные необходимо отправлять без задержки, так как активный пользователь всегда смотрит на экран в ожидании данных.

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

Сжатие данных

Сжатие с помощью WebSockets — это не тема, которая часто обсуждается. Но если необходимо отправить большие объемы данных в режиме реального времени, полезно использовать метод сжатия.

Однако, чтобы добиться сжатия данных с помощью WebSockets, и клиент, и сервер должны согласиться с этим.
Знаете ли вы, что WebSockets предоставляет расширение для сжатия данных?

Когда клиент инициирует согласование, объявляя расширение permessage-deflate в заголовке Sec-Websocket-Extensions, сервер должен подтвердить объявленное расширение, повторив его в своем ответе.

Инициирование клиента:

GET /socket HTTP/1.1
Host: thirdparty.com
Origin: http://example.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Extensions: permessage-deflate

Ответ сервера:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Access-Control-Allow-Origin: http://example.com
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Extensions: permessage-deflate

Безопасность веб-сокетов

WebSockets позволяет неограниченному количеству сообщений попадать на сервер. Это может легко дать злоумышленнику доступ для выполнения DoS-атаки.

Следовательно, важно использовать механизм аутентификации для обеспечения безопасности. Одним из распространенных способов использования является использование токенов JWT, которые ускоряют проверку подписи запроса.

Кроме того, очень важно использовать wss вместо ws, который защитит туннель связи, аналогично HTTPS.

Совместимость с браузером

WebSockets имеют хорошую совместимость практически со всеми браузерами. Также, в WebSockets есть встроенная связь между источниками. Он позволяет общаться с любой стороной в любом домене. Это можно контролировать, определяя домены, с которыми сервер может взаимодействовать, что повышает безопасность.

Кроме того, популярные реализации WebSockets, такие как socket.IO (NodeJS) или SignalR (.NET), поддерживают возврат к HTTP в старых браузерах.

Заключение

Когда вам нужно более качественное соединение с малой задержкой между клиентом и сервером, WebSockets — ваш лучший вариант.

Однако интеграция WebSockets в существующую веб-инфраструктуру может вызывать затруднения, поскольку для этого требуется изменение архитектуры. Кроме того, вы также можете взглянуть на шаблон Event Sourcing, который эффективно использует WebSockets для связи.

Вы можете посмотреть демонстрацию подключения WebSocket здесь. Спасибо за внимание.

Автор: Viduni Wickramarachchi

Источник: blog.bitsrc.io

Редакция: Команда webformyself.