WebSocket: особенности протокола и пример использования на React
Авторизуйтесь
WebSocket: особенности протокола и пример использования на React
Руководитель группы разработки digital-интегратора DD Planet
Интернет — основа сети, техническая инфраструктура, благодаря которой и существует World Wide Web, или Всемирная паутина. По своей сути интернет — гигантская сеть компьютеров, которые могут взаимодействовать друг с другом.
Принципы взаимодействия и способы передачи данных между этими компьютерами определяются сетевыми протоколами. Иными словами, сетевой протокол — это набор правил и действий, который регулирует соединение и обмен данными между двумя и более включенными в сеть устройствами.
В этой статье я расскажу про популярный в наше время протокол — WebSocket. Он используется, как правило, при разработке приложений, в которых содержимое обновляется с высокой частотой или в реальном времени.
Описание
WebSocket обеспечивает обмен данными между браузером и сервером через постоянное соединение. Это двунаправленный, полнодуплексный протокол, который используется в сценарии взаимодействия «Клиент-сервер». Он начинается с ws:// или wss:// в случае безопасного соединения.
Принцип веб-сокета — соединение между клиентом и сервером остается активным до тех пор, пока оно не будет разорвано любой из сторон.
Соединение WebSocket устанавливается посредством HTTP-запроса:
Особенности протокола
О плюсах WebSocket:
Где применяется WebSocket
WebSocket может быть очень полезен для повышения скорости работы сайта. Но не стоит использовать этот протокол в случаях, когда мы хотим получать старые или неизменные данные, или необходимо загрузить данные лишь один раз. В таких кейсах стоит применить протокол HTTP.
Где используется WebSocket:
WebSocket подходит для этих проектов лучше всего, так как в них клиент может не выполнять на своей стороне никаких вычислений, а лишь получать\передавать данные на сервер.
Легкость протокола позволяет с высокой частотой отправлять или получать информацию. Например, моментально отображать обновления в онлайн-игре, когда соперник выполнил определенные действия, или загружать данные с наименьшей задержкой на трейдерской платформе, что будет положительно сказываться на результате торгов.
Пример из практики
В качестве примера покажу React-component, работающий с веб-сокетом. Его суть проста — отображать текущее состояние соединения и функциональность принудительного закрытия и открытия соединения.
Сервер веб-сокета — ресурс wss://ws.kraken.com/, который с определённой периодичностью отправляет клиентам сообщение о том, что сервер работает.
Использование протокола WebSocket в React-приложении выглядит так:
Протокол WebSocket позволяет быстро и безопасно пересылать данные на любой домен, помогает увеличить скорость сайта или приложения. Он поддерживается всеми популярными браузерами: Google Chrome, Apple Safari, Mozilla Firefox, Opera и Internet Explorer, что делает его универсальным.
WebSocket: что это, когда следует использовать и какие преимущества дает
Существуют разные способы передачи данных от браузера или приложения к серверам и обратно.
Правила этих способов описаны в специальных протоколах. Некоторые применяют там, где нет необходимости обмениваться данными быстро, например на информационных сайтах, другие там, где важна скорость, в частности в интернете вещей.
Мы совместно с экспертами из компании Git in Sky решили рассказать об одной из таких технологий — протоколе передачи данных веб-сокет (WebSocket) — и объяснить принцип его работы и преимущества на простых примерах.
Чтобы понять, что такое протокол WebSocket, давайте посмотрим, каким был интернет до него
Раньше, чтобы получить новую информацию от сервера, клиент (браузер) должен был направить ему запрос, а сервер отправлял ответ. Без запроса не было ответа, то есть обновления страницы — сервер не мог ничего отправить сам. Например, пользователь получил сообщение или push-уведомление на сайте. Чтобы клиент об этом узнал, он должен опрашивать сервер с некоторой периодичностью, нет ли новых данных.
Другой вариант — клиент узнавал о новых данных только тогда, когда пользователь взаимодействовал с сайтом: переходил на другие страницы, вручную обновлял вкладку или открывал сайт заново. Как правило, использовался первый метод: клиент, к примеру, раз в 5 секунд отправлял запрос на сервер; если было что-то новое, сервер отдавал эту информацию в ответ.
В таком подходе были недостатки:
Веб-сокеты же позволяют устанавливать постоянное соединение, и теперь сервер может сам отправить клиенту новые данные, не дожидаясь запроса. Эта интерактивность устраняет вышеперечисленные недостатки. Чтобы увидеть преимущества протокола WebSocket, посмотрим, как он работает, сравнив его с протоколом HTTP.
Как работает WebSocket и в чем его отличия от HTTP
Протокол HTTP однонаправленный. После цикла «запрос — ответ» соединение закрывается, а любой следующий запрос каждый раз устанавливает новое соединение с сервером: сколько запросов, столько и соединений. Процесс передачи данных происходит с некоторыми задержками за счет того, что есть накладные расходы на установку нового соединения при каждом запросе/ответе, а также сетевая и серверная нагрузка из-за обилия периодических запросов. В чистом виде протокол HTTP сейчас используется все реже, ему на смену приходит HTTPS. Это не отдельный протокол, а надстройка над HTTP, позволяющая шифровать данные.
Протокол WebSocket двунаправленный, полнодуплексный, что означает, что он может одновременно и получать, и передавать информацию. Веб-сокет делает это множество раз в одном открытом соединении. У такого соединения и скорость выше, чем у HTTP.
У веб-сокетов также есть возможность шифровать передаваемые данные, для этого используется надстройка над протоколом — WSS. Если передаваемые данные не зашифрованы, они становятся объектом для привлечения таких угроз, как несанкционированный доступ к клиенту третьих сторон, использование вредоносного ПО. Специальные надстройки протоколов передачи данных кодируют информацию на стороне отправителя и раскодируют на стороне получателя, оставляя ее зашифрованной для любых посредников. Так достигается безопасный транспортный уровень.
Для наглядности покажем, в чем различия технологий HTTP и WebSocket, на примере их работы в чатах.
Чтобы пользователи могли получать новые сообщения, браузер периодически опрашивал сервер: есть ли новые сообщения для пользователя? Каждый такой запрос устанавливал новое соединение и создавал лишнюю сетевую нагрузку.
Схема обмена сообщениями через HTTP-протокол
Как работает JS: WebSocket и HTTP/2+SSE. Что выбрать?
В этот раз мы поговорим о коммуникационных протоколах, сопоставим и обсудим их особенности и составные части. Тут мы займёмся технологиями WebSocket и HTTP/2, в частности, поговорим о безопасности и поделимся советами, касающимися выбора подходящих протоколов в различных ситуациях.
Введение
В наши дни сложные веб-приложения, обладающие насыщенными динамическими пользовательскими интерфейсами, воспринимаются как нечто само собой разумеющееся. А ведь интернету пришлось пройти долгий путь для того, чтобы достичь его сегодняшнего состояния.
В самом начале интернет не был рассчитан на поддержку подобных приложений. Он был задуман как коллекция HTML-страниц, как «паутина» из связанных друг с другом ссылками документов. Всё было, в основном, построено вокруг парадигмы HTTP «запрос/ответ». Клиентские приложения загружали страницы и после этого ничего не происходило до того момента, пока пользователь не щёлкнул мышью по ссылке для перехода на очередную страницу.
Примерно в 2005-м году появилась технология AJAX и множество программистов начало исследовать возможности двунаправленной связи между клиентом и сервером. Однако, все сеансы HTTP-связи всё ещё инициировал клиент, что требовало либо участия пользователя, либо выполнения периодических обращений к серверу для загрузки новых данных.
«Двунаправленный» обмен данными по HTTP
Технологии, которые позволяют «упреждающе» отправлять данные с сервера на клиент существуют уже довольно давно. Среди них — Push и Comet.
Один из наиболее часто используемых приёмов для создании иллюзии того, что сервер самостоятельно отправляет данные клиенту, называется «длинный опрос» (long polling). С использованием этой технологии клиент открывает HTTP-соединение с сервером, который держит его открытым до тех пор, пока не будет отправлен ответ. В результате, когда у сервера появляются данные для клиента, он их ему отправляет.
Вот пример очень простого фрагмента кода, реализующего технологию длинного опроса:
Эта конструкция представляет собой функцию, которая сама себя вызывает после того, как, в первый раз, будет запущена автоматически. Она задаёт 10-секундный интервал для каждого асинхронного Ajax-обращению к серверу, а после обработки ответа сервера снова выполняется планирование вызова функции.
Ещё одна используемая в подобной ситуации техника — это Flash или составной запрос HXR, и так называемые htmlfiles.
У всех этих технологий одна и та же проблема: дополнительная нагрузка на систему, которую создаёт использование HTTP, что делает всё это неподходящим для организации работы приложений, где требуется высокая скорость отклика. Например, это что-то вроде многопользовательской браузерной «стрелялки» или любой другой онлайн-игры, действия в которой выполняются в режиме реального времени.
Введение в технологию WebSocket
Спецификация WebSocket определяет API для установки соединения между веб-браузером и сервером, основанного на «сокете». Проще говоря, это — постоянное соединение между клиентом и сервером, пользуясь которыми клиент и сервер могут отправлять данные друг другу в любое время.
Посмотрим, как установка такого соединения выглядит со стороны клиента:
Вот упрощённый пример заголовков исходного запроса.
После установки соединения в ответе сервера будут сведения о переходе на протокол WebSocket:
После этого вызывается событие open в экземпляре WebSocket на клиенте:
Теперь, после завершения фазы рукопожатия, исходное HTTP-соединение заменяется на WebSocket-соединение, которое использует то же самое базовое TCP/IP-соединение. В этот момент и клиент и сервер могут приступать к отправке данных.
Благодаря использованию WebSocket можно отправлять любые объёмы данных, не подвергая систему ненужной нагрузке, вызываемой использованием традиционных HTTP-запросов. Данные передаются по WebSocket-соединению в виде сообщений, каждое из которых состоит из одного или нескольких фреймов, содержащих отправляемые данные (полезную нагрузку). Для того, чтобы обеспечить правильную сборку исходного сообщения по достижению им клиента, каждый фрейм имеет префикс, содержащий 4-12 байтов данных о полезной нагрузке. Использование системы обмена сообщениями, основанной на фреймах, помогает сократить число служебных данных, передаваемых по каналу связи, что значительно уменьшает задержки при передаче информации.
Стоит отметить, что клиенту будет сообщено о поступлении нового сообщения только после того, как будут получены все фреймы и исходная полезная нагрузка сообщения будет реконструирована.
Различные URL протокола WebSocket
При построении URL-адресов используются определённые правила. Особенностью URL WebSocket является то, что они не поддерживают якоря ( #sample_anchor ).
В остальном к URL WebSocket применяются те же правила, что и к URL HTTP. При использовании ws-адресов соединение оказывается незашифрованным, по умолчанию применяется порт 80. При использовании wss требуется TLS-шифрование и применяется порт 443.
Протокол работы с фреймами
Взглянем поближе на протокол работы с фреймами WebSocket. Вот что можно узнать о структуре фрейма из соответствующего RFC:
Если говорить о версии WebSocket, стандартизированной RFC, то можно сказать, что в начале каждого пакета имеется небольшой заголовок. Однако, устроен он довольно сложно. Вот описание его составных частей:
Данные во фреймах
API для передачи данных по протоколу WebSocket устроено очень просто:
Узнать, что находится внутри фреймов WebSocket-соединения, можно с помощью вкладки Network (Сеть) инструментов разработчика Chrome:
Фрагментация данных
Логика объединения фреймов, в общих чертах, выглядит так:
Благодаря фрагментации сервер может подобрать буфер разумного размера, а, когда буфер заполняется, отправлять данные в сеть. Второй вариант использования фрагментации заключается в мультиплексировании, когда нежелательно, чтобы сообщение занимало весь логический канал связи. В результате для целей мультиплексирования нужно иметь возможность разбивать сообщения на более мелкие фрагменты для того, чтобы лучше организовать совместное использование канала.
О heartbeat-сообщениях
В любой момент после процедуры рукопожатия, либо клиент, либо сервер, может решить отправить другой стороне ping-сообщение. Получая такое сообщение, получатель должен отправить, как можно скорее, pong-сообщение. Это и есть heartbeat-сообщения. Их можно использовать для того, чтобы проверить, подключён ли ещё клиент к серверу.
Подобная схема обмена сообщениями может быть очень полезной. Есть службы (вроде балансировщиков нагрузки), которые останавливают простаивающие соединения.
Вдобавок, одна из сторон не может, без дополнительных усилий, узнать о том, что другая сторона завершила работу. Только при следующей отправке данных вы можете выяснить, что что-то пошло не так.
Обработка ошибок
Закрытие соединения
Вот как инициируют операцию закрытия WebSocket-соединения на клиенте:
Кроме того, для того, чтобы произвести очистку после завершения закрытия соединения, можно подписаться на событие close :
Серверу нужно прослушивать событие close для того, чтобы, при необходимости, его обработать:
Сравнение технологий WebSocket и HTTP/2
Хотя HTTP/2 предлагает множество возможностей, эта технология не может полностью заменить существующие push-технологии и потоковые способы передачи данных.
Первое, что важно знать об HTTP/2, заключается в том, что это — не замена всего, что есть в HTTP. Виды запросов, коды состояний и большинство заголовков остаются такими же, как и при использовании HTTP. Новшества HTTP/2 заключаются в повышении эффективности передачи данных по сети.
Если сравнить HTTP/2 и WebSocket, мы увидим много общих черт.
| Показатель | HTTP/2 | WebSocket |
| Сжатие заголовков | Да (HPACK) | Нет |
| Передача бинарных данных | Да | Да (бинарные или текстовые) |
| Мультиплексирование | Да | Да |
| Приоритизация | Да | Нет |
| Сжатие | Да | Да |
| Направление | Клиент/Сервер и Server Push | Двунаправленная передача данных |
| Полнодуплексный режим | Да | Да |
Как уже было сказано, HTTP/2 вводит технологию Server Push, которая позволяет серверу отправлять данные в клиентский кэш по собственной инициативе. Однако, при использовании этой технологии данные нельзя отправлять прямо в приложение. Данные, отправленные сервером по своей инициативе, обрабатывает браузер, при этом нет API, которые позволяют, например, уведомить приложение о поступлении данных с сервера и отреагировать на это событие.
Именно в подобной ситуации весьма полезной оказывается технология Server-Sent Events (SSE). SSE — это механизм, который позволяет серверу асинхронно отправлять данные клиенту после установления клиент-серверного соединения.
Так как технология SSE основана на HTTP, она отлично сочетается с HTTP/2. Её можно скомбинировать с некоторыми возможностями HTTP/2, что открывает дополнительные перспективы. А именно, HTTP/2 даёт эффективный транспортный уровень, основанный на мультиплексированных каналах, а SSE даёт приложениям API для передачи данных с сервера.
Для того, чтобы в полной мере понять возможности мультиплексирования и потоковой передачи данных, взглянем на определение IETF: «поток» — это независимая, двунаправленная последовательность фреймов, передаваемых между клиентом и сервером в рамках соединения HTTP/2. Одна из его основных характеристик заключается в том, что одно HTTP/2-соединение может содержать несколько одновременно открытых потоков, причём, любая конечная точка может обрабатывать чередующиеся фреймы из нескольких потоков.
Технология SSE основана на HTTP. Это означает, что с использованием HTTP/2 не только несколько SSE-потоков могут передавать данные в одном TCP-соединении, но то же самое может быть сделано и с комбинацией из нескольких наборов SSE-потоков (отправка данных клиенту по инициативе сервера) и нескольких запросов клиента (уходящих к серверу).
Благодаря HTTP/2 и SSE теперь имеется возможность организации двунаправленных соединений, основанных исключительно на возможностях HTTP, и имеется простое API, которое позволяет обрабатывать в клиентских приложениях данные, поступающие с серверов. Недостаточные возможности в сфере двунаправленной передачи данных часто рассматривались как основной недостаток при сравнении SSE и WebSocket. Благодаря HTTP/2 подобного недостатка больше не существует. Это открывает возможности по построению систем обмена данными между серверными и клиентскими частями приложений исключительно с использованием возможностей HTTP, без привлечения технологии WebSocket.
WebSocket и HTTP/2. Что выбрать?
Несмотря на чрезвычайно широкое распространение связки HTTP/2+SSE, технология WebSocket, совершенно определённо, не исчезнет, в основном из-за того, что она отлично освоена и из-за того, что в весьма специфических случаях у неё есть преимущества перед HTTP/2, так как она была создана для обеспечения двустороннего обмена данными с меньшей дополнительной нагрузкой на систему (например, это касается заголовков).
Предположим, вы хотите создать онлайн-игру, которая нуждается в передаче огромного количества сообщений между клиентами и сервером. В подобном случае WebSocket подойдёт гораздо лучше, чем комбинация HTTP/2 и SSE.
В целом, можно порекомендовать использование WebSocket для случаев, когда нужен по-настоящему низкий уровень задержек, приближающийся, при организации связи между клиентом и сервером, к обмену данными в реальном времени. Помните, что такой подход может потребовать переосмысления того, как строится серверная часть приложения, а также то, что тут может потребоваться обратить внимание на другие технологии, вроде очередей событий.
Если вам нужно, например, показывать пользователям в реальном времени новости или рыночные данные, или вы создаёте чат-приложение, использование связки HTTP/2+SSE даст вам эффективный двунаправленный канал связи, и, в то же время — преимущества работы с технологиями из мира HTTP. А именно, технология WebSocket нередко становится источником проблем, если рассматривать её с точки зрения совместимости с существующей веб-инфраструктурой, так как её использование предусматривает перевод HTTP-соединения на совершенно другой протокол, ничего общего с HTTP не имеющий. Кроме того, тут стоит учесть соображения масштабируемости и безопасности. Компоненты веб-систем (файрволы, средства обнаружения вторжений, балансировщики нагрузки) создают, настраивают и поддерживают с оглядкой на HTTP. В результате, если говорить об отказоустойчивости, безопасности и масштабируемости, для больших или очень важных приложений лучше подойдёт именно HTTP-среда.
Кроме того, во внимание стоит принять и поддержку технологий браузерами. Посмотрим, как с этим дела обстоят у WebSocket:
Тут всё выглядит очень даже прилично. Однако, в случае с HTTP/2 всё уже не так:
Тут можно отметить следующие особенности поддержки HTTP/2 в разных браузерах:
Не поддерживают эту технологию лишь IE/Edge. (Да, Opera Mini не поддерживает ни SSE, ни WebSocket, поэтому поддержку в этом браузере мы можем, сравнивая эти технологии, и не учитывать.) Однако, для IE/Edge существуют достойные полифиллы.
Итоги
Как видите, у технологий WebSockets и HTTP/2+SSE есть, в сравнении друг с другом, и преимущества, и недостатки. Что же всё-таки выбрать? Пожалуй, на этот вопрос поможет ответить лишь анализ конкретного проекта и всесторонний учёт его требований и особенностей. Возможно, помощь при принятии решения окажет знание того, как эти технологии используют в уже существующих проектах. Так, автор этого материала говорит, что они, в SessionStack, используют, в зависимости от ситуации, и WebSockets, и HTTP.
Когда библиотеку SessionStack интегрируют в веб-приложение, она начинает собирать и записывать все изменения DOM, события, возникающие при взаимодействии с пользователем, JS-исключения, результаты трассировки стека, неудачные сетевые запросы, отладочные сообщения, позволяя воспроизводить проблемные ситуации и наблюдать за всем, что происходит при работе пользователя с приложением. Всё это происходит в режиме реального времени и не должно влиять на производительность веб-приложения. Администратор может наблюдать за сеансом работы пользователя прямо в процессе работы этого пользователя. В этом сценарии в SessionStack решили использовать HTTP, так как двунаправленный обмен данными тут не нужен (сервер просто передаёт данные в браузер). Использование в подобной ситуации WebSocket было бы неоправданно, привело бы к усложнению поддержки и масштабирования решения. Однако, библиотека SessionStack, интегрируемая в веб-приложение, использует WebSocket, и, только если организовать обмен данными по WebSocket невозможно, переходит на HTTP.
Библиотека собирает данные в пакеты и отправляет на сервера SessionStack. В настоящее время реализуется лишь передача данных с клиента на сервер, но не наоборот, однако, некоторые возможности библиотеки, которые появятся в будущем, требуют двунаправленного обмена данными, именно поэтому здесь и используется технология WebSocket.
Уважаемые читатели! Пользовались ли вы технологиями WebSocket и HTTP/2+SSE? Если да — просим рассказать о том, какие задачи вы с их помощью решали, и о том, как вам понравилось то, что получилось.
WebSocket
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/websocket.
Протокол WebSocket (стандарт RFC 6455) предназначен для решения любых задач и снятия ограничений обмена данными между браузером и сервером.
Он позволяет пересылать любые данные, на любой домен, безопасно и почти без лишнего сетевого трафика.
Пример браузерного кода
У объекта socket есть четыре колбэка: один при получении данных и три – при изменениях в состоянии соединения:
…Или файл, выбранный в форме:
Для того, чтобы коммуникация была успешной, сервер должен поддерживать протокол WebSocket.
Чтобы лучше понимать происходящее – посмотрим, как он устроен.
Установление WebSocket-соединения
Протокол WebSocket работает над TCP.
Это означает, что при соединении браузер отправляет по HTTP специальные заголовки, спрашивая: «поддерживает ли сервер WebSocket?».
Если сервер в ответных заголовках отвечает «да, поддерживаю», то дальше HTTP прекращается и общение идёт на специальном протоколе WebSocket, который уже не имеет с HTTP ничего общего.
Установление соединения
Пример запроса от браузера при создании нового объекта new WebSocket(«ws://server.example.com/chat») :
GET, Host Стандартные HTTP-заголовки из URL запроса Upgrade, Connection Указывают, что браузер хочет перейти на websocket. Origin Протокол, домен и порт, откуда отправлен запрос. Sec-WebSocket-Key Случайный ключ, который генерируется браузером: 16 байт в кодировке Base64. Sec-WebSocket-Version Версия протокола. Текущая версия: 13.
Затем данные передаются по специальному протоколу, структура которого («фреймы») изложена далее. И это уже совсем не HTTP.
Расширения и подпротоколы
Посмотрим разницу между ними на двух примерах:
Заголовок Sec-WebSocket-Extensions: deflate-frame означает, что браузер поддерживает модификацию протокола, обеспечивающую сжатие данных.
Это говорит не о самих данных, а об улучшении способа их передачи. Браузер сам формирует этот заголовок.
Заголовок Sec-WebSocket-Protocol: soap, wamp говорит о том, что по WebSocket браузер собирается передавать не просто какие-то данные, а данные в протоколах SOAP или WAMP («The WebSocket Application Messaging Protocol»). Стандартные подпротоколы регистрируются в специальном каталоге IANA.
Этот заголовок браузер поставит, если указать второй необязательный параметр WebSocket :
При наличии таких заголовков сервер может выбрать расширения и подпротоколы, которые он поддерживает, и ответить с ними.
Кроме большей безопасности, у WSS есть важное преимущество перед обычным WS – большая вероятность соединения.
Дело в том, что HTTPS шифрует трафик от клиента к серверу, а HTTP – нет.
Если между клиентом и сервером есть прокси, то в случае с HTTP все WebSocket-заголовки и данные передаются через него. Прокси имеет к ним доступ, ведь они никак не шифруются, и может расценить происходящее как нарушение протокола HTTP, обрезать заголовки или оборвать передачу.
Формат данных
Полное описание протокола содержится в RFC 6455.
Здесь представлено частичное описание с комментариями самых важных его частей. Если вы хотите понять стандарт, то рекомендуется сначала прочитать это описание.
Описание фрейма
В протоколе WebSocket предусмотрены несколько видов пакетов («фреймов»).
Они делятся на два больших типа: фреймы с данными («data frames») и управляющие («control frames»), предназначенные для проверки связи (PING) и закрытия соединения.
Фрейм, согласно стандарту, выглядит так:
С виду – не очень понятно, во всяком случае, для большинства людей.
Позвольте пояснить: читать следует слева-направо, сверху-вниз, каждая горизонтальная полоска это 32 бита.
То есть, вот первые 32 бита:
Сначала идёт бит FIN (вертикальная надпись на рисунке), затем биты RSV1, RSV2, RSV3 (их смысл раскрыт ниже), затем «опкод», «МАСКА» и, наконец, «Длина тела», которая занимает 7 бит. Затем, если «Длина тела» равна 126 или 127, идёт «Расширенная длина тела», потом (на следующей строке, то есть после первых 32 бит) будет её продолжение, ключ маски, и потом данные.
А теперь – подробное описание частей фрейма, то есть как именно передаются сообщения:
Одно сообщение, если оно очень длинное (вызовом send можно передать хоть целый файл), может состоять из множества фреймов («быть фрагментированным»).
RSV1, RSV2, RSV3: 1 бит каждый
Задаёт тип фрейма, который позволяет интерпретировать находящиеся в нём данные. Возможные значения:
Если этот бит установлен, то данные фрейма маскированы. Более подробно маску и маскирование мы рассмотрим далее.
Длина тела: 7 битов, 7+16 битов, или 7+64 битов
Такая хитрая схема нужна, чтобы минимизировать накладные расходы. Для сообщений длиной 125 байт и меньше хранение длины потребует всего 7 битов, для бóльших (до 65536) – 7 битов + 2 байта, ну а для ещё бóльших – 7 битов и 8 байт. Этого хватит для хранения длины сообщения размером в гигабайт и более.
Ключ маски: 4 байта.
Если бит Маска установлен в 0, то этого поля нет. Если в 1 то эти байты содержат маску, которая налагается на тело (см. далее).
Данные фрейма (тело)
Состоит из «данных расширений» и «данных приложения», которые идут за ними. Данные расширений определяются конкретными расширениями протокола и по умолчанию отсутствуют. Длина тела должна быть равна указанной в заголовке.
Примеры
Некоторые примеры сообщений:
Нефрагментированное текстовое сообщение Hello без маски:
Фрагментированное текстовое сообщение Hello World из трёх частей, без маски, может выглядеть так:
А теперь посмотрим на все те замечательные возможности, которые даёт этот формат фрейма.
Фрагментация
Позволяет отправлять сообщения в тех случаях, когда на момент начала посылки полный размер ещё неизвестен.
Например, идёт поиск в базе данных и что-то уже найдено, а что-то ещё может быть позже.
PING / PONG
В протокол встроена проверка связи при помощи управляющих фреймов типа PING и PONG.
Тот, кто хочет проверить соединение, отправляет фрейм PING с произвольным телом. Его получатель должен в разумное время ответить фреймом PONG с тем же телом.
Эта функциональность встроена в браузерную реализацию, так что браузер ответит на PING сервера, но управлять ей из JavaScript нельзя.
Иначе говоря, сервер всегда знает, жив ли посетитель или у него проблема с сетью.
Чистое закрытие
При закрытии соединения сторона, желающая это сделать (обе стороны в WebSocket равноправны) отправляет закрывающий фрейм (опкод 0x8 ), в теле которого указывает причину закрытия.
Наличие такого фрейма позволяет отличить «чистое закрытие» от обрыва связи.
Коды закрытия
1000 Нормальное закрытие. 1001 Удалённая сторона «исчезла». Например, процесс сервера убит или браузер перешёл на другую страницу. 1002 Удалённая сторона завершила соединение в связи с ошибкой протокола. 1003 Удалённая сторона завершила соединение в связи с тем, что она получила данные, которые не может принять. Например, сторона, которая понимает только текстовые данные, может закрыть соединение с таким кодом, если приняла бинарное сообщение.
Атака «отравленный кэш»
В ранних реализациях WebSocket существовала уязвимость, называемая «отравленный кэш» (cache poisoning).
Она позволяла атаковать кэширующие прокси-сервера, в частности, корпоративные.
Атака осуществлялась так:
Хакер заманивает доверчивого посетителя (далее Жертва) на свою страницу.
Страница формирует специального вида WebSocket-запрос, который (и здесь самое главное!) ряд прокси серверов не понимают.
Они пропускают начальный запрос через себя (который содержит Connection: upgrade ) и думают, что далее идёт уже следующий HTTP-запрос.
Прокси послушно проглотит этот ответ и закэширует «якобы jQuery».
В результате при загрузке последующих страниц любой пользователь, использующий тот же прокси, что и Жертва, получит вместо http://code.jquery.com/jquery.js хакерский код.
Поэтому эта атака и называется «отравленный кэш».
Такая атака возможна не для любых прокси, но при анализе уязвимости было показано, что она не теоретическая, и уязвимые прокси действительно есть.
Поэтому придумали способ защиты – «маску».
Маска для защиты от атаки
Для того, чтобы защититься от атаки, и придумана маска.
Ключ маски – это случайное 32-битное значение, которое варьируется от пакета к пакету. Тело сообщения проходит через XOR ^ с маской, а получатель восстанавливает его повторным XOR с ней (можно легко доказать, что (x ^ a) ^ a == x ).
Маска служит двум целям:
Наложение маски требует дополнительных ресурсов, поэтому протокол WebSocket не требует её.
Пример
Рассмотрим прототип чата на WebSocket и Node.JS.
HTML: посетитель отсылает сообщения из формы и принимает в div








