Real-Time Backend

WebSocket Protocol (RFC 6455)

2008 год. Slack не существует. Совместная работа - это email и IRC. Michael Mahemoff формулирует проблему: HTTP не предназначен для двунаправленной коммуникации в реальном времени. Long polling - костыль, который создаёт тысячи hanging HTTP соединений на серверах. Google Wave (2009) демонстрирует collaborative editing - и рушит любой сервер под нагрузкой. Ian Hickson начинает работу над WebSocket как частью HTML5. RFC 6455 принят в 2011 году. Slack, Figma, multiplayer games - всё это стало возможным благодаря одному апгрейду поверх TCP.

  • **Slack**: каждое сообщение в реальном времени - WebSocket с fallback на SSE
  • **Figma**: collaborative editing - все курсоры и изменения через WebSocket
  • **Биржи**: market data feeds (тысячи обновлений/сек) - WebSocket единственная опция
  • **Multiplayer games**: game state sync через бинарные WebSocket frames для минимального overhead

От Comet до RFC 6455

В 2006 году Alex Russell (Dojo Toolkit) ввёл термин 'Comet' для описания техник эмуляции push: long polling, forever frame, XMLHttpRequest streaming. Всё это были хаки - HTTP не был предназначен для этого. В 2008 году Ian Hickson из Google начал разработку WebSocket API как части HTML5. Первые реализации появились в 2010 году. После обнаружения уязвимостей (WebSocket bypass proxy cache poisoning) протокол был доработан: добавлена маскировка клиентских фреймов. RFC 6455 принят IETF в декабре 2011 года. Сегодня WebSocket поддерживают все браузеры и большинство load balancers.

WebSocket Handshake

WebSocket соединение начинается с HTTP Upgrade handshake - клиент просит переключить протокол с HTTP на WebSocket на существующем TCP соединении.

**Sec-WebSocket-Key / Accept:** Случайный ключ клиента + фиксированный GUID (MAGIC) = SHA1 хэш. Это предотвращает случайные WebSocket handshakes от HTTP клиентов которые не ожидают WebSocket ответа. Не является криптографической безопасностью.

Почему WebSocket использует HTTP Upgrade вместо отдельного TCP соединения на другом порту?

WebSocket Framing

После handshake данные передаются в WebSocket фреймах. Минимальный overhead: 2 байта для маленьких сообщений vs сотни байт HTTP headers.

WebSocket сообщение в 200 байт отправляется с клиента на сервер. Какой минимальный overhead в байтах на заголовок фрейма?

Opcodes и типы фреймов

WebSocket определяет несколько типов фреймов (opcodes). Data frames передают данные, Control frames управляют соединением.

OpcodeHexТипОписание
0x00ContinuationПродолжение фрагментированного сообщения
0x11TextUTF-8 текст (обязательна валидация UTF-8)
0x22BinaryБинарные данные (произвольные байты)
0x88CloseЗапрос закрытия соединения
0x99PingHeartbeat запрос
0xA10PongОтвет на Ping

**Ping/Pong критически важны в production.** Load balancers (AWS ALB, Nginx) закрывают idle WebSocket соединения после timeout (обычно 60-300 сек). Без Ping клиент не узнает что соединение разорвано - будет пытаться слать в никуда. Реализуй Ping каждые 20-30 секунд.

Multiplayer игра отправляет позицию игрока 30 раз/секунду: {x: 125.4, y: 89.2, angle: 1.57}. Text или Binary frame?

Close Handshake и коды статуса

WebSocket предусматривает корректное двустороннее закрытие соединения. Простое закрытие TCP без Close handshake - антипаттерн.

КодЗначениеКогда использовать
1000Normal ClosureНормальное завершение работы
1001Going AwayСервер перезагружается или страница закрывается
1002Protocol ErrorНарушение протокола WebSocket
1003Unsupported DataНеожиданный тип данных (binary вместо text)
1006Abnormal ClosureНет close frame (TCP разрыв) - только локально
1007Invalid Frame PayloadНевалидный UTF-8 в text frame
1008Policy ViolationНарушение политики (например, rate limit)
1011Internal ErrorСерверная ошибка

WebSocket автоматически переподключается при разрыве соединения

WebSocket не имеет встроенного reconnect. Приложение должно реализовать reconnect логику с Exponential Backoff.

RFC 6455 определяет только протокол фреймирования. Reconnect, heartbeat, message ordering - ответственность приложения. Библиотеки типа Socket.IO добавляют эти возможности поверх голого WebSocket.

WebSocket соединение разорвано из-за network outage. Клиент получает событие close с кодом 1006. Что это означает?

Ключевые идеи

  • **Handshake**: HTTP Upgrade request/response - переключение протокола на существующем TCP соединении
  • **Framing**: минимальный overhead - 2-14 байт на фрейм (vs HTTP headers в сотни байт)
  • **Opcodes**: Text (0x1), Binary (0x2), Close (0x8), Ping (0x9), Pong (0xA)
  • **Masking**: клиент маскирует payload XOR 4-байтным ключом - защита от proxy cache poisoning
  • **Close handshake**: корректное закрытие через Close frame с кодом причины

Вопросы для размышления

  • Почему WebSocket использует HTTP Upgrade вместо нового порта? Что это говорит о совместимости с firewall и proxy?
  • Маскировка клиентских фреймов защищает от proxy cache poisoning - но увеличивает CPU overhead. Как это влияет на выбор Text vs Binary frames?
  • WebSocket не имеет встроенного механизма heartbeat - почему Ping/Pong опкоды критически важны для production deployment?

Связанные уроки

  • rt-03-sse
  • rt-05
  • net-06-ip-intro
  • rt-06
  • net-03-physical
  • net-15-tcp-basics
WebSocket Protocol (RFC 6455)

0

1

Войти