Веб сокеты что это
Примечание. Клиент не может использовать WebSocket для передачи данных, если сервер не использует протокол WebSocket. Если сервер не поддерживает WebSocket, вам придется использовать другой метод передачи данных.
Защита подключения с помощью TLS/SSL
В большинстве случаев необходимо использовать безопасное подключение WebSocket, чтобы зашифровать отправляемые и получаемые данные. Это также увеличивает шансы успешного подключения, так как многие посредники, такие как брандмауэры и прокси-серверы, отклоняют незашифрованные подключения WebSocket. Протокол WebSocket определяет эти две схемы URI.
Схема универсального кода ресурса (URI) | Цель |
---|---|
wss: | Используется для защищенных соединений, которые должны быть зашифрованы. |
ws: | Используется для незашифрованных соединений. |
Чтобы зашифровать подключение WebSocket, воспользуйтесь схемой URI wss: . Ниже приведен пример.
Использование сокета MessageWebSocket для подключения
Обработка событий MessageWebSocket.MessageReceived и MessageWebSocket.Closed
Как показано в приведенном выше примере, до установки подключения и отправки данных с помощью MessageWebSocket необходимо подписаться на события MessageWebSocket.MessageReceived и MessageWebSocket.Closed.
Событие MessageReceived создается при получении данных. Доступ к данным осуществляется через MessageWebSocketMessageReceivedEventArgs. Событие Closed создается, когда клиент или сервер закрывает сокет.
Отправка данных в MessageWebSocket
После установки подключения можно отправлять данные на сервер. Это можно сделать с помощью свойства MessageWebSocket.OutputStream и DataWriter для записи данных.
Примечание. DataWriter становится владельцем потока вывода. Когда DataWriter выходит за пределы области, если к нему прикреплен поток вывода, DataWriter освобождает поток вывода. После этого все последующие попытки использовать поток вывода будут неудачными со значением HRESULT 0x80000013. Но можно вызвать метод DataWriter.DetachStream, чтобы отсоединить поток вывода от DataWriter и вернуть владение потоком событию MessageWebSocket.
Использование StreamWebSocket для подключения
Обработка события StreamWebSocket.Closed
Прежде чем устанавливать подключение и отправлять данные с помощью StreamWebSocket, необходимо подписаться на событие StreamWebSocket.Closed. Событие Closed создается, когда клиент или сервер закрывает сокет.
Отправка данных в StreamWebSocket
После установки подключения можно отправлять данные на сервер. Это можно сделать с помощью свойства StreamWebSocket.OutputStream и DataWriter для записи данных.
Примечание. Если вы хотите записать больше данных в один сокет, не забудьте вызвать метод DataWriter.DetachStream, чтобы отсоединить поток вывода от DataWriter до того, как DataWriter выйдет за пределы области. В результате владельцем потока становится MessageWebSocket.
Получение данных в StreamWebSocket
Дополнительные параметры для MessageWebSocket и StreamWebSocket
Прежде чем устанавливать подключение, можно задать дополнительные параметры в сокете, задав свойства в MessageWebSocketControl или StreamWebSocketControl. Вы осуществляете доступ к экземпляру этих классов из самого объекта сокета через его свойство MessageWebSocket.Control или StreamWebSocket.Control в зависимости от ситуации.
Вот пример использования StreamWebSocket. Такая же схема применяется к MessageWebSocket.
Примечание. Не пытайтесь изменить свойство элемента управления после вызова ConnectAsync. Единственное исключение из этого правила — MessageWebSocketControl.MessageType.
Классы информации WebSocket
MessageWebSocket и StreamWebSocket имеют соответствующий класс, который обеспечивает дополнительную информацию об объекте.
MessageWebSocketInformation предоставляет информацию о MessageWebSocket, и вы извлекаете его экземпляр с помощью свойства MessageWebSocket.Information.
StreamWebSocketInformation предоставляет информацию о StreamWebSocket, и вы извлекаете его экземпляр с помощью свойства StreamWebSocket.Information.
Обратите внимание, что свойства в этих классах информации доступны только для чтения, но их можно использовать для извлечения информации в любой момент в течение срока жизни объекта веб-сокета.
Обработка исключений
Ошибка, обнаруженная в операции MessageWebSocket или StreamWebSocket, возвращается в виде значения HRESULT. Можно передать значение HRESULT методу WebSocketError.GetStatus, чтобы преобразовать его в значение перечисления WebErrorStatus.
Для ошибок при проверке параметров можно использовать также значение HRESULT из исключения, чтобы получить подробные сведения об ошибке. Возможные значения HRESULT перечислены в Winerror.h , который находится в вашей установке SDK (например, в папке C:\Program Files (x86)\Windows Kits\10\Include\<VERSION>\shared ). Для многих ошибок при проверке параметров HRESULT возвращает значение E_INVALIDARG.
Назначение времени ожидания при выполнении операций с WebSocket
Чтобы ускорить реакцию приложения и свести эти проблемы к минимуму, можно задать более короткое время ожидания для запросов на подключение. Время ожидания задается одинаково для MessageWebSocket и StreamWebSocket.
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Протокол WebSocket (стандарт RFC 6455) предназначен для решения любых задач и снятия ограничений обмена данными между браузером и сервером.
Он позволяет пересылать любые данные, на любой домен, безопасно и почти без лишнего сетевого трафика.
Пример браузерного кода
Для открытия соединения достаточно создать объект WebSocket , указав в нём специальный протокол ws .:
У объекта socket есть четыре колбэка: один при получении данных и три – при изменениях в состоянии соединения:
Для посылки данных используется метод socket.send(data) . Пересылать можно любые данные.
…Или файл, выбранный в форме:
Просто, не правда ли? Выбираем, что переслать, и socket.send() .
Для того, чтобы коммуникация была успешной, сервер должен поддерживать протокол WebSocket.
Чтобы лучше понимать происходящее – посмотрим, как он устроен.
Установление WebSocket-соединения
Протокол WebSocket работает над TCP.
Установление соединения
Все заголовки, кроме GET и Host , браузер генерирует сам, без возможности вмешательства JavaScript.
Сервер может проанализировать эти заголовки и решить, разрешает ли он WebSocket с данного домена Origin .
Ответ сервера, если он понимает и разрешает WebSocket -подключение:
Здесь строка Sec-WebSocket-Accept представляет собой перекодированный по специальному алгоритму ключ Sec-WebSocket-Key . Браузер использует её для проверки, что ответ предназначается именно ему.
Расширения и подпротоколы
Также возможны дополнительные заголовки Sec-WebSocket-Extensions и Sec-WebSocket-Protocol , описывающие расширения и подпротоколы (subprotocol), которые поддерживает данный клиент.
Посмотрим разницу между ними на двух примерах:
Заголовок Sec-WebSocket-Extensions: deflate-frame означает, что браузер поддерживает модификацию протокола, обеспечивающую сжатие данных.
Это говорит не о самих данных, а об улучшении способа их передачи. Браузер сам формирует этот заголовок.
Заголовок Sec-WebSocket-Protocol: soap, wamp говорит о том, что по WebSocket браузер собирается передавать не просто какие-то данные, а данные в протоколах SOAP или WAMP («The WebSocket Application Messaging Protocol»). Стандартные подпротоколы регистрируются в специальном каталоге IANA.
Этот заголовок браузер поставит, если указать второй необязательный параметр WebSocket :
При наличии таких заголовков сервер может выбрать расширения и подпротоколы, которые он поддерживает, и ответить с ними.
В ответе выше сервер указывает, что поддерживает расширение deflate-frame , а из запрошенных подпротоколов – только SOAP.
Кроме большей безопасности, у WSS есть важное преимущество перед обычным WS – большая вероятность соединения.
А в случае с WSS весь трафик сразу кодируется и через прокси проходит уже в закодированном виде. Поэтому заголовки гарантированно пройдут, и общая вероятность соединения через WSS выше, чем через WS .
Формат данных
Полное описание протокола содержится в RFC 6455.
Здесь представлено частичное описание с комментариями самых важных его частей. Если вы хотите понять стандарт, то рекомендуется сначала прочитать это описание.
Описание фрейма
В протоколе WebSocket предусмотрены несколько видов пакетов («фреймов»).
Они делятся на два больших типа: фреймы с данными («data frames») и управляющие («control frames»), предназначенные для проверки связи (PING) и закрытия соединения.
Фрейм, согласно стандарту, выглядит так:
С виду – не очень понятно, во всяком случае, для большинства людей.
Позвольте пояснить: читать следует слева-направо, сверху-вниз, каждая горизонтальная полоска это 32 бита.
То есть, вот первые 32 бита:
Сначала идёт бит FIN (вертикальная надпись на рисунке), затем биты RSV1, RSV2, RSV3 (их смысл раскрыт ниже), затем «опкод», «МАСКА» и, наконец, «Длина тела», которая занимает 7 бит. Затем, если «Длина тела» равна 126 или 127, идёт «Расширенная длина тела», потом (на следующей строке, то есть после первых 32 бит) будет её продолжение, ключ маски, и потом данные.
У всех фреймов, кроме последнего, этот фрагмент установлен в 0 , у последнего – в 1 .
RSV1, RSV2, RSV3: 1 бит каждый
В обычном WebSocket равны 0 , предназначены для расширений протокола. Расширение может записать в эти биты свои значения.
Задаёт тип фрейма, который позволяет интерпретировать находящиеся в нём данные. Возможные значения:
Если этот бит установлен, то данные фрейма маскированы. Более подробно маску и маскирование мы рассмотрим далее.
Длина тела: 7 битов, 7+16 битов, или 7+64 битов
Если значение поле «Длина тела» лежит в интервале 0-125 , то оно обозначает длину тела (используется далее). Если 126 , то следующие 2 байта интерпретируются как 16-битное беззнаковое целое число, содержащее длину тела. Если 127 , то следующие 8 байт интерпретируются как 64-битное беззнаковое целое, содержащее длину.
Ключ маски: 4 байта.
Если бит Маска установлен в 0, то этого поля нет. Если в 1 то эти байты содержат маску, которая налагается на тело (см. далее).
Данные фрейма (тело)
Состоит из «данных расширений» и «данных приложения», которые идут за ними. Данные расширений определяются конкретными расширениями протокола и по умолчанию отсутствуют. Длина тела должна быть равна указанной в заголовке.
Примеры
В заголовке первый байт содержит FIN=1 и опкод=0x1 (получается 10000001 в двоичной системе, то есть 0x81 – в 16-ричной), далее идёт длина 0x5 , далее текст.
А теперь посмотрим на все те замечательные возможности, которые даёт этот формат фрейма.
Фрагментация
Например, идёт поиск в базе данных и что-то уже найдено, а что-то ещё может быть позже.
PING / PONG
В протокол встроена проверка связи при помощи управляющих фреймов типа PING и PONG.
Тот, кто хочет проверить соединение, отправляет фрейм PING с произвольным телом. Его получатель должен в разумное время ответить фреймом PONG с тем же телом.
Эта функциональность встроена в браузерную реализацию, так что браузер ответит на PING сервера, но управлять ей из JavaScript нельзя.
Иначе говоря, сервер всегда знает, жив ли посетитель или у него проблема с сетью.
Чистое закрытие
При закрытии соединения сторона, желающая это сделать (обе стороны в WebSocket равноправны) отправляет закрывающий фрейм (опкод 0x8 ), в теле которого указывает причину закрытия.
В браузерной реализации эта причина будет содержаться в свойстве reason события onclose .
Наличие такого фрейма позволяет отличить «чистое закрытие» от обрыва связи.
В браузерной реализации событие onclose при чистом закрытии имеет event.wasClean = true .
Коды закрытия
Атака «отравленный кэш»
В ранних реализациях WebSocket существовала уязвимость, называемая «отравленный кэш» (cache poisoning).
Она позволяла атаковать кэширующие прокси-сервера, в частности, корпоративные.
Атака осуществлялась так:
Хакер заманивает доверчивого посетителя (далее Жертва) на свою страницу.
Прокси послушно проглотит этот ответ и закэширует «якобы jQuery».
Поэтому эта атака и называется «отравленный кэш».
Такая атака возможна не для любых прокси, но при анализе уязвимости было показано, что она не теоретическая, и уязвимые прокси действительно есть.
Поэтому придумали способ защиты – «маску».
Маска для защиты от атаки
Для того, чтобы защититься от атаки, и придумана маска.
Маска служит двум целям:
Наложение маски требует дополнительных ресурсов, поэтому протокол WebSocket не требует её.
Если по этому протоколу связываются два клиента (не обязательно браузеры), доверяющие друг другу и посредникам, то можно поставить бит Маска в 0 , и тогда ключ маски не указывается.
В статье рассказывается, как использовать веб-сокеты для создания веб-приложений. Но перед тем как погрузиться в изучение протокола и API веб-сокетов, рассмотрим проблемы, с которыми сталкиваются веб-приложения, и как WebSocket помогает их решению.
Краткая история веб-приложений реального времени
Интернет был построен на представлении о том, что забота браузера– запрос данных с сервера, а забота сервера – обслуживание этих запросов. Эта парадигма не подвергалась сомнению несколько лет. Но с появлением AJAX в 2005 году многие начали работать над созданием двунаправленных соединений.
Чтобы решить данную проблему, нужен был способ создания постоянного соединения с минимальными задержками, которое могло бы поддерживать транзакции, инициированные как клиентом, так и сервером. Это как раз то, что предоставляют веб-сокеты.
Как работают веб-сокеты
Веб-сокет создает постоянное соединение между клиентом и сервером, которое обе стороны могут использовать для отправки данных.
Вот упрощённый пример первоначальных заголовков запроса.
Если сервер поддерживает протокол WebSocket, он сообщает об этом с помощью заголовка Upgrade в ответе.
Date : Wed, 16 Oct 2013 10:07:34 GMT
Создаём демо-пример
Создание приложения на основе веб-сокетов
Мы создадим простое приложение, которое соединяется с сервером по веб-сокету. Перед тем, как мы углубимся в детали API, нужно создать несколько файлов.
Посмотреть на CodePen
Создайте файл index.html и добавьте в него следующую разметку.
Файл style.css , на который ссылается этот код, находится в архиве для загрузки. Далее создадим файл app.js и добавим в него следующий код.
Мы создали несколько переменных и инициализировали их ссылками на ключевые элементы страницы.
Открытие соединений
Теперь, когда готов костяк приложения, можно начать изучать WebSocket API. Для начала узнаем, как создать новое соединение WebSocket. Для этого нужно вызвать конструктор класса WebSocket и передать ему URL сервера.
Скопируйте следующий код в файл app.js , чтобы создать новое соединение.
Добавьте следующий код в файл app.js .
Также мы добавляем класс open элементу <div> .
Обработка ошибок
Обработка ошибок осуществляется через событие error . Добавьте следующий код, который будет записывать ошибки в консоль.
Можно отправлять как текст, так и двоичные данные. В нашем приложении нужно передавать содержимое текстового поля на сервер при отправке формы. Чтобы сделать это, надо определить обработчик события отправки формы.
Добавьте следующий код в файл app.js .
Чтобы добиться этого, скопируйте следующий код в файл app.js .
Закрытие соединений
Когда вы закончите работу с веб-сокетом, нужно разорвать соединение, используя метод close() .
После того, как соединение будет разорвано, браузер вызовет событие close . Добавление обработчика события close позволит выполнить любую «уборку», которая потребуется.
Теперь нам нужно обновить статус соединения при его разрыве. Добавьте следующий код в файл app.js :
Чтобы завершить приложение, нужно добавить обработчик события, который будет вызываться при нажатии кнопки «Close Connection». Он должен вызывать метод close() объекта WebSocket.
Наше приложение готово!
Мониторинг трафика веб-сокета с помощью инструментов для разработчиков в Chrome
«Инструменты разработчика», доступные в браузере Google Chrome включают в себя средства для мониторинга трафика. Чтобы использовать этот инструмент:
- Откройте «Инструменты разработчика».
- Перейдите на вкладку Network.
- Кликните по записи, соответствующей вашему соединению по веб-сокету.
- Перейдите на вкладку Frames.
Эти инструменты предоставляют общую информацию о данных, переданных через соединение.
WebSocket на сервере
В этой статье мы сфокусировали внимание на том, как использовать веб-сокеты на стороне клиента. Если вы хотите создать собственный сервер WebSocket, существует множество библиотек, которые могут в этом помочь. Одна из наиболее популярных – socket.io , библиотека Node.JS.
- C++: libwebsockets ;
- Erlang: Shirasu.ws ;
- Java: Jetty ;
- Node.JS: ws ;
- Ruby: em-websocket ;
- Python: Tornado , pywebsocket ;
- PHP: Ratchet , phpws .
Поддержка браузерами
Веб-сокеты поддерживаются практически во всех современных браузерах. Единственными исключениями являются Android- браузеры и Opera Mini.
Заключительные мысли
В этой статье вы узнали о протоколе WebSocket. А также том, как использовать его API для создания веб-приложений, работающих в режиме реального времени.
WebSocket – это большой шаг в эволюции интернета. Возможность создания соединения с низкими затратами ресурсов открывает путь к новому поколению веб-приложений.
Дайте знать, что вы думаете по этой теме статьи в комментариях. Мы крайне благодарны вам за ваши комментарии, дизлайки, отклики, подписки, лайки!
Пожалуйста, оставьте свои отзывы по текущей теме материала. Мы очень благодарим вас за ваши комментарии, подписки, дизлайки, лайки, отклики!
p, blockquote 1,0,0,0,0 -->
p, blockquote 2,0,0,0,0 -->
В отличии от сокетов транспортного уровня, которые являются интерфейсом, через которые протоколы прикладного уровня обращаются к сервисам транспортного уровня, web сокет это протокол, который описывает правила взаимодействия между разными хостами на прикладном уровне.
p, blockquote 3,0,0,0,0 -->
p, blockquote 4,0,0,0,0 -->
p, blockquote 5,0,0,0,0 -->
p, blockquote 6,0,0,0,0 -->
p, blockquote 7,0,0,0,0 -->
p, blockquote 8,0,0,0,0 -->
p, blockquote 9,0,0,0,0 -->
Web Сокеты
p, blockquote 10,0,1,0,0 -->
p, blockquote 11,0,0,0,0 -->
p, blockquote 12,0,0,0,0 -->
Web сокеты это стандартный протокол, который определенно в RFC 6455 в 2011 году уже достаточно давно и сейчас он поддерживается всеми современными браузерами. В web сокетах на прикладном уровне устанавливается постоянное двунаправленное соединение между клиентом и сервером. При этом на транспортном уровне также используется постоянное соединение tcp.
p, blockquote 13,0,0,0,0 -->
p, blockquote 14,0,0,0,0 -->
p, blockquote 15,0,0,0,0 -->
p, blockquote 16,0,0,0,0 -->
p, blockquote 17,0,0,0,0 -->
Ключ используется для защиты от фальшивых запросов на установку соединения с веб сокетами. Также в заголовке указывается версия веб сокетов, текущая версия 13.
p, blockquote 18,0,0,0,0 -->
p, blockquote 19,0,0,0,0 -->
p, blockquote 20,0,0,0,0 -->
p, blockquote 21,1,0,0,0 -->
Передача данных
p, blockquote 22,0,0,0,0 -->
Фрагментация
p, blockquote 23,0,0,0,0 -->
Типы кадров
В web сокетах есть кадры трех типов:
- кадры, которые передают текстовую информацию представленную в кодировке utf-8;
- кадры, которые передают данные в двоичном виде;
- управляющие кадре которые используются для поддержания или для закрытия соединения.
Запрос ping
Для поддержания соединения используются запросы ping-pong, сервер через определенные промежутки времени отправляет клиенту управляющий запрос ping и после того как клиент получил этот запрос он в ответ отправляет управляющий кадр pong.
p, blockquote 25,0,0,0,0 -->
p, blockquote 26,0,0,0,0 -->
Это нужно для того чтобы решить две задачи: п ервое, убедиться, что другая сторона соединение все еще функционирует, а вторая задача это поддерживать TCP соединения открытым в случае если клиент и сервер соединены не напрямую, а например через прокси сервер или балансировщик нагрузки.
p, blockquote 27,0,0,0,0 -->
Разрыв соединения
p, blockquote 28,0,0,0,0 -->
p, blockquote 29,0,0,0,0 -->
Формат заголовка кадра Web сокетов
Заголовок кадра в веб сокетах выглядит вот таким образом. Эта картинка из документа rfc.
p, blockquote 30,0,0,0,0 -->
p, blockquote 31,0,0,1,0 -->
Основные поля здесь это код операции (opcode), который говорит о том, что за тип кадра. Э то может быть кадр, который передает текстовые данные, бинарные данные, кадр ping, pong, close и другие типы кадров.
p, blockquote 32,0,0,0,0 -->
В разделе Payload Data находится полезные данные, которые нужно передать. В веб сокетах для того чтобы снизить накладные расходы используется хитрая схема для указания объема передаваемых данных. Если объем данных небольшой, то для поля длина данных используется всего лишь 7 бит, а если объем данных больше, то могут использоваться дополнительные биты заголовка и размер поля длина данных может быть 16 или 64 бита.
p, blockquote 33,0,0,0,0 -->
В первой части кадра находятся флаги. Первый вид флаг FIN используются для указания фрагментации, если этот флаг равен единице. то значит текущий кадр является последним. при этом если данные поместились в один кадр целиком и фрагментации нет. то флаг FIN установлен в единицу.
p, blockquote 34,0,0,0,0 -->
p, blockquote 35,0,0,0,0 -->
А если данные были фрагментированны и передаются в нескольких кадрах, то во всех кадрах кроме последнего фланг FIN установлен в 0. Следующие три флага, зарезервированны и используются для расширения протокола веб советов. О том будут ли использоваться расширение и какие именно клиенту и серверу необходимо договориться в процессе установки соединения.
p, blockquote 36,0,0,0,0 -->
В веб сокетах данные при передаче могут маскироваться и на практике это делается почти всегда, если данные маскируются то флаг MASK установлен в единицу, в противном случае в 0. Если используется маскирование данных, то кадр должен включать ключ маскирование, Masking-key.
p, blockquote 37,0,0,0,0 -->
К люч маскирование генерируется отправителем случайным образом и этот ключ должен быть разным для каждого кадра, если используются маскирование, то в части Payload Data находятся данные, которые получены в результате операции xor ключа маскирования и оригинальных данных.
p, blockquote 38,0,0,0,0 -->
Заключение
Мы рассмотрели протокол веб сокетов, который позволяет организовать веб двунаправленную асинхронную передачи данных. Веб сокеты очень полезны для разработки web-приложений реального времени.
p, blockquote 39,0,0,0,0 -->
p, blockquote 40,0,0,0,0 -->
p, blockquote 41,0,0,0,0 --> p, blockquote 42,0,0,0,1 -->
Читайте также: