Spec-Zone.ru › Socket.IO 4

Как это работает

Двунаправленный канал между сервером Socket.IO (Node.js) и клиентом Socket.IO (браузер, Node.js или другой язык программирования) устанавливается с помощью соединения WebSocket, если это возможно, а в качестве резервного варианта используется HTTP-долговое опрос.

Код Socket.IO разделен на два отдельных уровня:

  • нижний уровень: то, что мы называем Engine.IO, движок внутри Socket.IO
  • высокоуровневый API: сам Socket.IO

Engine.IO

Engine.IO отвечает за установление соединения низкого уровня между сервером и клиентом. Он обрабатывает:

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

Исходный код можно найти здесь:

  • сервер: https://github.com/socketio/engine.io
  • клиент: https://github.com/socketio/engine.io-client
  • парсер: https://github.com/socketio/engine.io-parser
  • описание протокола: https://github.com/socketio/engine.io-protocol

Транспортные средства

В настоящее время реализованы два транспортных средства:

  • HTTP-долговое опрос
  • WebSocket

HTTP-долговое опрос

Транспорт HTTP-долгового опроса (также просто «опрос») состоит из последовательных HTTP-запросов:

  • долгоработающие GET запросы для получения данных с сервера
  • кратковременные POST запросы для отправки данных на сервер

В силу особенностей транспортного средства, последовательные отправки могут быть конкатенированы и отправлены в одном HTTP-запросе.

WebSocket

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

Из-за особенностей транспортного средства каждая отправка отправляется в отдельной WebSocket-рамке (некоторые отправки могут даже привести к двум отдельным WebSocket-рамкам, дополнительная информация здесь).

Установление соединения

В начале соединения Engine.IO сервер отправляет некоторую информацию:

{
  "sid": "FSDjX-WRwSA4zTZMALqx",
  "upgrades": ["websocket"],
  "pingInterval": 25000,
  "pingTimeout": 20000
}
  • значение sid является идентификатором сессии, оно должно быть включено в sid параметр запроса во всех последующих HTTP-запросах
  • массив upgrades содержит список всех «лучших» транспортных средств, поддерживаемых сервером
  • значения pingInterval и pingTimeout используются в механизме «сердцебиения»

Механизм обновления

По умолчанию клиент устанавливает соединение с транспортным средством HTTP-долгового опроса.

Но почему?

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

С точки зрения пользователя, неудачное подключение WebSocket может привести к ожиданию до как минимум 10 секунд, прежде чем приложение реального времени начнет обмен данными. Это существенно негативно сказывается на пользовательском опыте.

Подводя итог, Engine.IO фокусируется на надежности и пользовательском опыте в первую очередь, второстепенное значение придается потенциальному улучшению UX и увеличению производительности сервера.

Для обновления клиент:

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

Вы можете проверить это в мониторе сети вашего браузера:

Successful upgrade

  1. установление соединения (содержит идентификатор сессии — здесь, zBjrh...AAAK — который используется в последующих запросах)
  2. отправка данных (HTTP-долговое опрос)
  3. получение данных (HTTP-долговое опрос)
  4. обновление (WebSocket)
  5. получение данных (HTTP-долговое опрос, закрывается, как только соединение WebSocket в пункте 4 успешно установлено)

Обнаружение отключения

Соединение Engine.IO считается закрытым, когда:

  • один HTTP-запрос (GET или POST) завершается неудачно (например, при остановке сервера)
  • соединение WebSocket закрывается (например, при закрытии вкладки пользователем в браузере)
  • socket.disconnect() вызывается на стороне сервера или клиента

Также существует механизм «сердцебиения», который проверяет, что соединение между сервером и клиентом по-прежнему активно:

С заданным интервалом (значение pingInterval отправленное при установлении соединения) сервер отправляет пакет PING, а у клиента есть несколько секунд (значение pingTimeout ) чтобы отправить пакет PONG обратно. Если сервер не получает пакет PONG обратно, он считает, что соединение закрыто. Аналогично, если клиент не получает пакет PING в течение pingInterval + pingTimeout, он считает, что соединение закрыто.

Причины отключения перечислены здесь (на стороне сервера) и здесь (на стороне клиента).

Socket.IO

Socket.IO предоставляет дополнительные функции над соединением Engine.IO:

  • автоматическое переподключение
  • буферизация пакетов
  • подтверждения
  • вещание всем клиентам или подмножеству клиентов (то, что мы называем «Комнатой»)
  • мультиплексирование (то, что мы называем «Пространством имен»)

Исходный код можно найти здесь:

  • сервер: https://github.com/socketio/socket.io
  • клиент: https://github.com/socketio/socket.io-client
  • парсер: https://github.com/socketio/socket.io-parser
  • описание протокола: https://github.com/socketio/socket.io-protocol

© 2014–2021 Automattic
Licensed under the MIT License.
https://socket.io/docs/v4/how-it-works

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API