От автора: в приложениях реального времени само собой разумеется, что нам нужно получать информацию с серверов, как только она станет доступной — и, по сути, классическая парадигма HTTP — запрос/ответ не подходит. Это потому, что сервер будет молчать, есть ли новые данные или нет, до тех пор, пока не будет отправлен запрос.
Это ограничение привело к появлению всевозможных хаков и обходных решений, поскольку разработчики стремились адаптировать модель запроса/ответа к требованиям более динамичной сети реального времени, некоторые из которых стали формализованными и довольно широко распространенными.
Все эти технологии и подходы — от Comet до длинного поллинга HTTP — имеют одну общую черту: по сути, они призваны создать иллюзию реального (событийного) обмена данными, поэтому, когда на сервере появляются какие-то новые данные, он отправляет ответ.
Несмотря на то, что HTTP не является протоколом, управляемым событиями, не в реальном времени, эти подходы на самом деле работают довольно хорошо в определенных случаях использования, например, в чате Gmail. Однако проблемы возникают в приложениях с малой задержкой или масштабировании, в основном из-за требований к обработке, связанных с HTTP.
TCP и UDP | Что это такое и в чем разница?
То есть с HTTP вы должны постоянно запрашивать обновления (и получать ответ), что очень ресурсоемко: клиент устанавливает соединение, запрашивает обновление, получает ответ от сервера, а затем закрывает соединение. Представьте, что этот процесс повторяется бесконечно тысячами одновременно работающих пользователей — это невероятно обременительно для масштабируемого сервера.
Именно эти проблемы в конечном итоге побудили разработчиков Майкла Картера и Яна Хиксона разработать WebSockets — по сути, тонкий транспортный уровень, построенный поверх стека TCP/IP. Идея состояла в том, чтобы предоставить веб-приложениям то, что по сути является коммуникационным уровнем TCP, максимально приближенным к исходному, исключив несколько абстракций, чтобы устранить определенные сложности, связанные с безопасностью, и другие проблемы.
Ранее мы писали о концептуальном глубоком погружении в WebSockets, а также освещали эволюцию HTTP и сравнивали HTTP/2 и HTTP/3, поэтому не будем возвращаться к этому здесь.
Вместо этого в этом посте будут рассмотрены некоторые методы, используемые для обхода ограничений парадигмы HTTP — запроса/ответа в приложениях реального времени, некоторые проблемы этой парадигмы и то, как WebSockets может помочь их преодолеть.
HTTP
HTTP — это, по сути, протокол запроса/ответа в клиент-серверной модели и основной режим связи в веб. Первоначальная версия, предложенная Тимом Бернерсом-Ли в 1989 году, была очень ограниченной и ее быстро изменили для поддержки более широкой функциональности браузера и сервера.
Эти модификации были в конечном итоге задокументированы рабочей группой HTTP в 1996 году как HTTP/1.0 (RFC 1945), хотя HTTP/1.0 не считается формальной спецификацией или стандартом.
БИТВА SRT против RTMP — ФИНАЛ! КАКОЙ ПРОТОКОЛ КРУЧЕ?
HTTP/1.1
HTTP/1.1 является наиболее широко поддерживаемой версией в веб-браузерах и на серверах, и его появление стало большим шагом вперед, потому что HTTP/1.1 позволил сделать некоторые довольно важные оптимизации и улучшения, от постоянных и конвейерных соединений до новых полей заголовка запроса/ответа. Главными из них являются два заголовка, которые служат основой для многих улучшений, помогающих сделать Интернет более динамичным в реальном времени.
HTTP-опрос
HTTP-опрос представляет собой шаг вперед по сравнению с классическим механизмом запроса/ответа — хотя, существуют различные версии опроса, но только длинный опрос каким-либо образом применим к приложениям реального времени.
Например, короткий опрос HTTP используется таймером на основе AJAX, чтобы клиентские устройства отправляли запросы к серверу через фиксированные интервалы. Однако сервер по-прежнему будет немедленно отвечать на каждый запрос, либо предоставляя новые данные, либо отправляя «пустой» ответ, если новых данных нет, перед закрытием соединения. Так что для приложений реального времени это принесет не так много пользы, когда клиенту нужно знать о новых данных, как только они становятся доступными.
Именно это ограничение привело к развитию длинного опроса HTTP, который, по сути, представляет собой метод, предназначенный для имитации функции отправки данных на сервер.
Что такое TCP/IP и как работает этот протокол
Протокол TCP/IP – это целая сетевая модель, описывающая способ передачи данных в цифровом виде. На правилах, включенных в нее, базируется работа интернета и локальных сетей независимо от их назначения и структуры.
Что такое TCP/IP
Произошло наименование протокола от сокращения двух английских понятий – Transmission Control Protocol и Internet Protocol. Набор правил, входящий в него, позволяет обрабатывать как сквозную передачу данных, так и другие детали этого механизма. Сюда входит формирование пакетов, способ их отправки, получения, маршрутизации, распаковки для передачи программному обеспечению.
Стек протоколов TCP/IP был создан в 1972 году на базе NCP (Network Control Protocol), в январе 1983 года он стал официальным стандартом для всего интернета. Техническая спецификация уровней взаимодействия описана в документе RFC 1122.
В составе стека есть и другие известные протоколы передачи данных – UDP, FTP, ICMP, IGMP, SMTP. Они представляют собой частные случаи применения технологии: например, у SMTP единственное предназначение заключается в отправке электронных писем.
Комьюнити теперь в Телеграм
Подпишитесь и будьте в курсе последних IT-новостей
Уровни модели TCP/IP
Протокол TCP/IP основан на OSI и так же, как предшественник, имеет несколько уровней, которые и составляют его архитектуру. Всего выделяют 4 уровня – канальный (интерфейсный), межсетевой, транспортный и прикладной.
Канальный (сетевой интерфейс)
Аппаратный уровень обеспечивает взаимодействие сетевого оборудования Ethernet и Wi-Fi. Он соответствует физическому из предыдущего стандарта OSI. Здесь задача состоит в кодировании информации, ее делению на пакеты и отправке по нужному каналу. Также измеряются параметры сигнала вроде задержки ответа и расстояния между хостами.
Межсетевой (Internet Layer)
Интернет состоит из множества локальных сетей, объединенных между собой как раз за счет протокола связи TCP/IP. Межсетевой уровень регламентирует взаимодействие между отдельными подсетями. Маршрутизация осуществляется путем обращения к определенному IP-адресу с использованием маски.
Если хосты находятся в одной подсети, маркируемой одной маской, данные передаются напрямую. В противном случае информация «путешествует» по целой цепочке промежуточных звеньев, пока не достигнет нужной точки. Назначение IP-адреса проводится по стандарту IPv4 или IPv6 (они не совместимы между собой).
Транспортный уровень (Transport Layer)
Следующий уровень отвечает за контроль доставки, чтобы не возникало дублей пакетов данных. В случае обнаружения потерь или ошибок информация запрашивается повторно. Такой подход дает возможность полностью автоматизировать процессы независимо от скорости и качества связи между отдельными участками интернета или внутри конкретной подсети.
Протокол TCP отличается большей достоверностью передачи данных по сравнению с тем же UDP, который подходит только для передачи потокового видео и игровой графики. Там некритичны потери части пакетов, чего нельзя сказать о копировании программных файлов и документов. На этом уровне данные не интерпретируются.
Прикладной уровень (Application Layer)
Здесь объединены 3 уровня модели OSI – сеансовый, представления и прикладной. На него ложатся задачи по поддержанию сеанса связи, преобразованию данных, взаимодействию с пользователем и сетью. На этом уровне применяются стандарты интерфейса API, позволяющего передавать команды на выполнение определенных задач.
Возможно и использование «производных» протоколов. Например, для открытия сайтов используется HTTPS, при отправке электронной почты – SMTP, для назначения IP-адресов – DHCP. Такой подход упрощает программирование, снижает нагрузку на сеть, увеличивает скорость обработки команд и передачи данных.
Порты и сокеты – что это и зачем они нужны
Процессы, работающие на прикладном уровне, «общаются» с транспортным, но они видны ему как «черные ящики» с зашифрованной информацией. Зато он понимает, на какой IP-адрес адресованы данные и через какой порт надо их принимать. Этого достаточно для точного распределения пакетов по сети независимо от месторасположения хостов. Порты с 0 до 1023 зарезервированы операционными системами, остальные, в диапазоне от 1024 до 49151, условно свободны и могут использоваться сторонними приложениями.
Комбинация IP-адреса и порта называется сокетом и используется при идентификации компьютера. Если первый критерий уникален для каждого хоста, второй обычно фиксирован для определенного типа приложений. Так, получение электронной почты проходит через 110 порт, передача данных по протоколу FTP – по 21, открытие сайтов – по 80.
Преобразование IP-адресов в символьные адреса
Технология активно используется для назначения буквенно-цифровых названий веб-ресурсов. При вводе домена в адресной строке браузера сначала происходит обращение к специальному серверу DNS. Он всегда прослушивает порт 53 у всех компьютеров, которые подключены к интернету, и по запросу преобразует введенное название в стандартный IP-адрес.
После определения точного местонахождения файлов сайта включается обычная схема работы – от прикладного уровня с кодированием данных до обращения к физическому оборудованию на уровне сетевых интерфейсов. Процесс называется инкапсуляцией информации. На принимающей стороне происходит обратная процедура – декапсуляция.
Источник: timeweb.com
Небольшое расследование: как YouTube использует WebRTC для стриминга
WebRTC — это JavaScript API в современных браузерах для видеозвонков. А еще для голосовых звонков, шаринга экрана, пробития NAT, раскрытия локального адреса и других интересных штук. В последние пару лет крупные игроки начинают переходить с пропиетарных API и расширений браузеров на WebRTC: с его помощью работает Skype for Web, частично — Hangouts, а теперь и возможности YouTube по броадкасту прямо из браузера. Пока только из хрома и с пятисекундной задержкой — но велика беда начало. Под катом мы предлагаем адаптированный для Хабра перевод детективной истории, где эксперты по WebRTC разбирают код клиентской части YouTube и рассказывают нам что и как сделали разработчики из Гугла.
Прошлый Четверг. Залогинившисть в свой YouTube аккаунт, я обнаружил новую иконку камеры с подсказкой «Go Live» в правом-верхнем углу (примечание переводчика: судя по всему, пока раскатано не для всех пользователей. В комментах отметились подписчики YouTube Red, у них есть). Естественно я сразу же ее кликнул, и, похоже, теперь мы можем стримить прямо из браузера.
Попахивало WebRTC, так что я привычно открыл chrome://webrtc-internals/ — и таки да, это было WebRTC. Нас как разработчиков всегда интересовали масштабные использования технологии, так что я сразу связался с мастером-реверсером Филипом «Фип» Ханкелем и попросил его покопаться во внутренностях YouTube. Дальше мы можем ознакомиться с результатами его работы.
Служебная страница Хрома, webrtc-internals, сослужила нам хорошую службу еще в далеком 2014 году, когда мы изучали как работает Hangouts, и ничего не мешало нам снова ей воспользоваться. Так как новая регистрация на YouTube недоступна для броадкастов в течении 24 часов, то мы воспользовались дампом, любезно предоставленным Цахи Левент-Леви (примечание переводчика: да-да, тот самый Цахи который выступал у нас на Intercom и которого мы регулярно переводим). Вы можете воспользоваться вот этой тулзой, чтобы загрузить дамп себе в Хром и посмотреть на происходящее глазами WebRTC.
Судя по тому, что мы увидели, новая фича YouTube использует WebRTC только на стороне клиента для захвата потока видеокамеры. А со стороны сервера у них что-то свое. Что это значит? Значит не realtime. Хотя наш давний и хороший знакомый Крис Кранки говорит, что задержка составляет менее пяти секунд.
Очень ждем, что он вытащит наружу какие-нибудь интересные технические детали.
А пока углубимся в технические детали, которые смогли вытащить мы…
Вызовы getUserMedia
После импортирования дампа, в самом его начале мы видим вызовы JavaScript API getUserMedia, которые совершает YouTube. По вызовам видно, что сервис скромно хочет камеру в разрешении 1080p:
А еще они делают отдельный вызов getUserMedia для получения микрофона.
На этом скриншоте не видно самого первого вызова getUserMedia, который запрашивает сразу камеру и микрофон, чтобы пользователь увидел только одно оконо подтверждения бразуера вместо двух.
Вызовы RTCPeerConnection
Осмотрев вызовы getUserMedia, можно переходить к вызовам RTCPeerConnection. Если вы хотите узнать больше о WebRTC, рекомендую почитать результаты предыдущего исследования » Как работает Hangouts» или более общую информацию о webrtc-internals на нашем блоге TestRTC blog.
Серверы ICE
По логу видно, что объект RTCPeerConnection создан с пустым списокм ICE серверов (примечание переводчика: неудивительно, что это пока работает только в Хроме. Ёжик бы вообще не дал такой объект создать).
Далее будет ясно, почему для такого варианта использования не нужны TURN-серверы (примечание переводчика: ICE это «фреймворк», текстовая инструкция как делать peer-to-peer с печальными IP адресами 192.168. TURN-серверы в фреймворке не самое главное. Самое главное это STUN-серверы, которые отвечают на фундаментальный вопрос «а какой у меня внешний IP адрес?». Без указания как минимум одного STUN-сервера большинство реализаций WebRTC просто не будет работать).
Далее клиент добавляет MediaStream с помощью API addSteam. Забавно, что это API объявлено depricated. Странно, что авторы не используют новое API addTrack, которое доступно начиная с 64-й версии Google Chrome, а в более старых версиях — с помощью полифила adapter.js
Сигнализация и setLocalDescription
После создания объекта RTCPeerConnection клиент создает WebRTC «оффер» со списком всех аудио и видео кодеков, доступных Хрому. Оффер без модификаций устанавливается как описание локального эндпоинта с помощью setLocalDescription. Кстати, отсутствие модификаций означает, что simulcast (одновременное транслирование нескольких потоков с разным качеством видео, позволяет не перекодировать все на сервере, уменьшает задержки и нагрузку) не используется.
В соответствии с логикой работы WebRTC, после вызова setLocalDescription хром предлагает несколько «кандидатов» — вариантов как удаленный компьютер может попробовать подключиться к локальному. Скорее всего они не используются, так как подключаться будет клиент (Хром) к серверу (бэкенду YouTube).
Апдейт: Найти сервер сигналинга и используемый протокол оказалось не очень сложно. Фильтр по ключевому слову «realtimemediaservice» сетевого лога Хрома показывают нам HTTP запрос и ответ на него. Никаких сложные схем, trickle-ice оптимизаций скорости установки соединения и другой магии, все настолько просто, насколько вообще возможно.
setRemoteDescription
Следующим шагом идет вызов setRemoteDescription на основании информации, полученной от сервера. Где, как мы помним, WebRTC не используется. И здесь все становится интересным! SDP, используемый в setRemoteDescription, выглядит так, как будто на другой стороне его сделал Хром или сишная WebRTC-библиотека с полным списком кодеков наперевес. Причем мы точно знаем, что YouTube не использует «ice-lite», как это делает Hangouts.
В полученном со стороны сервера SDP пакете кодек H.264 указан как предпочтительный (число 102, см здесь, если интересно, как устроены текстовые пакеты SDP):
m=video 9 UDP/TLS/RTP/SAVPF 102 96 97 98 99 123 108 109 124
Изучение статистики (частично отображается после загрузки дампа) подтверждает, что используется кодек H.264, кому любопытно можете поискать в дампе по ключевому слову «send-googCodecName».
Кроме SDP ответа, сервер передает Хрому несколько кандидатов для установки подключения:
a=candidate:3757856892 1 udp 2113939711 2a00:1450:400c:c06::7f 19305 typ host generation 0 network-cost 50 a=candidate:1687053168 1 tcp 2113939711 2a00:1450:400c:c06::7f 19305 typ host tcptype passive generation 0 network-cost 50 a=candidate:1545990220 1 ssltcp 2113939711 2a00:1450:400c:c06::7f 443 typ host generation 0 network-cost 50 a=candidate:4158478555 1 udp 2113937151 66.102.1.127 19305 typ host generation 0 network-cost 50 a=candidate:1286562775 1 tcp 2113937151 66.102.1.127 19305 typ host tcptype passive generation 0 network-cost 50 a=candidate:3430656991 1 ssltcp 2113937151 66.102.1.127 443 typ host generation 0 network-cost 50