Большинство материалов, связанных с WebRTC, относятся к прикладному уровню написания кода и не помогают понять технологию. Давайте погрузимся в тему глубже и узнаем, как устанавливается соединение, зачем нужны серверы TURN и STUN, что такое дешифратор и кандидаты сессии.

Введение

WebRTC — это технология, ориентированная на браузеры, которая позволяет подключаться к клиентам для передачи видеоданных. Внутренняя поддержка браузера (внешние технологии, такие как Adobe Flash, не нужны) и возможность подключения клиентов без использования дополнительных серверов (p2p-соединение) — основные особенности WebRTC.

p2p — соединение, при котором два человека взаимодействуют друг с другом без третьих лиц.

Установить p2p-соединение довольно сложно, поскольку компьютеры не всегда обладают публичными IP-адресами. Из-за малого количества адресов IPv4 и в целях безопасности был изобретен NAT. Он позволяет создавать частные сети, например, для домашнего использования. Многие домашние маршрутизаторы поддерживают NAT, поэтому все устройства, подключенные к маршрутизатору, имеют доступ в Интернет, хотя поставщики услуг обычно предоставляют один IP-адрес. Публичные IP-адреса уникальны, а частные — нет, поэтому p2p-подключение затруднено.

Чтобы лучше понять концепцию, давайте рассмотрим три сценария:

1. Оба узла находятся в одной сети

2. Оба узла находятся в разных сетях (частной и публичной)

3. Оба узла находятся в разных частных сетях с одинаковыми IP-адресами

Первая буква на изображениях выше обозначает тип узла: r — маршрутизатор, p — одноранговый узел.

  1. На первом изображении показана хорошая ситуация. Узлы в своих сетях идентифицируются с помощью сетевых IP-адресов, и они могут напрямую соединяться друг с другом.
  2. На изображении 2 показаны две разные сети с одинаково упорядоченными узлами. Здесь мы представляем маршрутизаторы, и они имеют два сетевых интерфейса: внутри и снаружи своей системы. Следовательно, у них два IP-адреса. Обычно узлы имеют только один интерфейс, и они используют его для взаимодействия внутри своей сети, а если они передают данные куда-то за пределами своей системы, то делают это только с помощью NAT внутри маршрутизатора. Вот почему эти узлы отображаются как IP-адрес маршрутизатора — это их внешний IP. Таким образом, узел p1 имеет внешний IP (10.50.200.5) и внутренний (192.168.0.200), причем первый адрес также является внешним для всех остальных узлов сети. Узел p2 в такой же ситуации, поэтому их соединение невозможно, пока используются только внутренние адреса. Можно использовать внешние IP-адреса, но это создает проблему, поскольку все узлы в одной частной сети имеют один и тот же внешний адрес. NAT решает эту проблему.
  3. Что произойдет, если мы решим соединить узлы через их внутренние адреса? Данные не покинут сеть. Чтобы усилить эффект, представьте ситуацию с третьего изображения, где оба узла имеют одинаковые внутренние адреса. Если они используют эти адреса для связи друг с другом, то оба будут общаться сами с собой.

Здесь на помощь приходит WebRTC. Для решения этих проблем WebRTC использует протокол ICE, который требует дополнительные сервера: STUN и TURN.

Две фазы WebRTC

Чтобы соединить два узла с помощью протокола WebRTC (или просто RTC, если речь идет о двух iPhone), необходимо выполнить несколько предварительных шагов для установления соединения. Это первая фаза. Вторая фаза — передача видеоданных.

Хотя WebRTC использует множество средств связи (TCP и UDP) и может гибко переключаться между ними, эта технология не имеет протокола для передачи данных о соединении. Это неудивительно, поскольку соединение двух p2p-узлов — задача не из простых. Исходя из этого, нам нужен дополнительный, не связанный с WebRTC, способ передачи данных. Это может быть протокол HTML, передача через сокет или протокол SMTP. Этот способ передачи начальных данных называется сигнальным механизмом. Передается не слишком много информации. Данные передаются в виде текста и делятся на две категории: SDP и Ice Candidate (вы также можете прочитать о них здесь) SDP используется для установления логического соединения, Ice Candidate — для физического соединения. Важно помнить, что WebRTC дает вам информацию, которую необходимо передать следующему узлу. Как только мы передадим необходимую информацию, узлы смогут соединиться, и наша помощь больше не понадобится. Поэтому сигнальный механизм, который мы должны создать отдельно, используется только при подключении, а не во время передачи видеоданных.

Итак, давайте рассмотрим первый этап. Он состоит из нескольких шагов. Сначала рассмотрим его для узла, инициирующего соединение, а затем для узла, принимающего соединение.

  • Инициатор (вызывающий узел):
  1. Получение локального медиапотока и установление его передачи (getUserMediaStream).
  2. Предложение начать передачу видеоданных (createOffer)
  3. Получение собственного объекта SDP и отправка его через механизм сигнализации (SDP)
  4. Получение собственных объектов Ice candidate и отправка их через механизм сигнализации (Ice candidate)
  5. Получение удаленного медиапотока и отображение его на экране (onAddStream)
  • Получатель (вызываемый узел)
  1. Получение локального медиапотока и установление его передачи (getUserMediaStream)
  2. Предложение начать передачу видеоданных и создание ответа (createAnswer)
  3. Получение собственного объекта SDP и отправка его через механизм сигнализации (SDP)
  4. Получение собственных объектов Ice candidate и отправка их через механизм сигнализации (Ice candidate)
  5. Получение удаленного медиапотока и отображение его на экране (на AddStream).

Только 2-й шаг отличается.

Какими бы сложными ни казались эти шаги, на самом деле их всего три: отправка локального медиапотока (шаг 1), установление параметров соединения (шаги 2-4), прием удаленного медиапотока (шаг 5). 2-й шаг является самым сложным, так как состоит из двух частей — нам необходимо установить логическое и физическое соединение. Последнее показывает путь, по которому должен следовать пакет, чтобы добраться от одного узла к другому, а первое указывает на параметры видео и аудио — какое качество и кодеки использовать.

Подключите шаги createOffer и createAnswer к шагам с передачей объектов SDP и Ice Candidate.

Вскоре мы рассмотрим некоторые сущности, такие как MediaStream, SDP и ice Candidate.

Основные сущности

MediaStream

MediaStream — это базовая сущность, состоящая из потоков видео и аудио данных. Существует два типа медиапотоков — локальные и удаленные. Локальные потоки получают данные от устройств ввода (камера, микрофон), удаленные потоки получают данные из сети.

Таким образом, каждый узел имеет локальный и удаленный потоки. В WebRTC для этих потоков существует интерфейс MediaStream, а также под-интерфейс LocalMediaStream, который существует специально для локального потока. В JavaScript вы можете столкнуться только с первым, но если вы используете libjingle, то можете столкнуться и со вторым.

WebRTC предполагает сложную иерархию внутри потока. Каждый поток состоит из нескольких медиадорожек (MediaTrack), которые могут состоять из нескольких медиаканалов (MediaChannel). Также может быть несколько медиапотоков.

Например, мы хотим передать не только видео с собой, но и стол с листом бумаги, на котором мы собираемся что-то написать. Нам понадобятся 2 видео (мы и стол) и 1 аудио (наше). Очевидно, что мы и стол должны быть разделены на разные потоки, так как они не очень зависят друг от друга. Поэтому у нас будет два медиапотока: один для нас и один для стола. Первый будет содержать видео- и аудиоданные, а второй — только видеоданные.

Медиапоток должен обеспечивать возможность хранения различных типов данных, а именно видео и аудио. Это учтено в технологии, поэтому каждый тип данных реализуется через MediaTrack (медиадорожки). MediaTrack имеет особое качество, называемое kind, которое определяет, что перед нами: видео или аудио.

Как же все происходит внутри программы? Мы создаем два медиапотока. Затем создадим две видеодорожки и одну аудиодорожку. Получим доступ к камере и микрофону. Скажем каждой дорожке, какую функцию она должна использовать. Добавим видео- и аудиодорожки в первый медиапоток, а видеодорожку со 2-й камеры — во второй медиапоток.

Как различать медиадорожки на другом конце? По функции label, которая есть у каждого медиаканала. Медиадорожки имеют одну и ту же функцию.

Итак, если мы можем идентифицировать медиадорожки с помощью метки, почему в данном примере нам нужно использовать две из них вместо одной? Вы можете передавать один медиапоток и использовать в нем разные дорожки. Теперь мы подошли к важной особенности медиадорожек — они синхронизируют медиадорожки. Различные медиадорожки не синхронизируются между собой, но все дорожки воспроизводятся одновременно в пределах каждой медиадорожки.

Поэтому, если мы хотим, чтобы наши слова, выражение лица и лист бумаги воспроизводились одновременно, нам нужно использовать одну и ту же медиадорожку. Если это не слишком важно, лучше использовать разные медиадорожки, чтобы изображение было более плавным.

Если дорожку нужно выключить во время передачи, мы можем использовать функцию enabled медиадорожки.

В заключение было бы неплохо подумать о стереозвуке. Стерео — это два разных звука, и их нужно передавать отдельно. Для этого используется MediaChannel. Медиадорожка может использовать различные каналы (например, 6, если нам нужен звук 5+1). Каналы внутри медиадорожки также синхронизируются. При воспроизведении видео обычно используется один канал, но можно использовать и несколько, например, для наложения рекламы.

Подведем итог: мы используем медиапоток для передачи видео- и аудиоданных. Данные синхронизируются внутри каждого медиапотока. Мы можем использовать разные медиаканалы, если не стремимся к синхронизации. Внутри каждого потока есть две медиадорожки — для видео и аудио. Дорожек может быть больше, если нам нужно передавать разные видео (собеседник и его стол). Каждая дорожка может состоять из разных каналов, но обычно используется только для стереозвука.

В простейшей ситуации у нас не будет видеочата, и будет только один локальный медиапоток из двух дорожек, аудио и видео. Каждая дорожка будет состоять из одного основного канала. Видеодорожка отвечает за камеру, а аудиодорожка — за микрофон. Медиапоток является контейнером для них обоих.

Дескриптор сессии (SDP)

На разных компьютерах стоят разные камеры, микрофоны, видеокарты и т.д. Существует множество их параметров. Все это необходимо согласовать для передачи медиаданных между двумя сетевыми узлами. WebRTC делает это автоматически и создает специальный объект — SDP. Передайте SDP другому узлу, и вы можете передавать видеоданные. Однако связи с другим узлом нет.

Здесь может помочь любой сигнальный механизм. SDP можно передавать через сокеты, через людей (передать SDP другому узлу по телефону), или… через обычную почту. Вы получаете готовый SDP, и его нужно отправить — вот так просто. Когда другой узел получает SDP, ему нужно отправить его в WebRTC. Он хранится в виде текста и может быть изменен из приложений, но это редко нужно. Как пример, при соединении десктоп <-> телефон, иногда приходится принудительно выбирать нужный аудиокодек.

Обычно при установлении соединения обязательно указывается адрес, например, URL. Здесь в этом нет необходимости, так как вы сами будете отправлять данные через механизм сигнализации. Чтобы сообщить WebRTC, что мы хотим установить p2p-соединение, необходимо вызвать функцию createOffer. После этого и создания специального обратного звонка появится новый объект SDP, который будет отправлен в тот же обратный вызов. Все, что вам нужно сделать, это передать этот объект другому узлу по сети.

Механизм сигнализации поможет данным прийти — этот объект SDP. Этот дескриптор сессии является чужим для данного узла, поэтому он несет полезную информацию.

Получение этого объекта — это сигнал к началу соединения. Поэтому нужно согласиться с ним и вызвать функцию createAnswer. Она является абсолютным аналогом createOffer. Ваш обратный звонок получит локальный дескриптор сессии, который затем нужно будет передать через сигнальный механизм обратно.

Стоит отметить, что вызов функции createAnswer возможен только после получения чужого объекта SDP. Это связано с тем, что локальный SDP-объект, который будет сгенерирован при вызове createAnswer, должен опираться на удаленный SDP-объект. Только тогда можно будет согласовать свои настройки видео с настройками собеседника. Также не следует вызывать createAnswer и createOffer до получения локального медиапотока, так как им будет нечего записывать в SDO-объект.

Поскольку WebRTC позволяет редактировать SDP-объект, вам нужно будет установить локальный дескриптор после его получения. Отправка того, что WebRTC передал нам обратно, может показаться странной, но таков протокол. Удаленный дескриптор также необходимо установить при получении.

После этого своеобразного рукопожатия узлы узнают о желаниях друг друга. Например, если узел 1 поддерживает кодеки A и B, а узел 2 поддерживает кодеки B и C, они оба выберут кодек B. Это потому, что эти узлы знают локальные и чужие дескрипторы. Логика соединения установлена, и теперь можно отправлять медиапотоки. Однако есть и другая проблема: узлы по-прежнему связаны только сигнальным механизмом.

Ice-кандидаты

При установлении соединения адрес узла, с которым нужно соединиться, не указывается. Сначала устанавливается логическое соединение, затем физическое, хотя раньше было наоборот. Однако это будет не так странно, если помнить, что мы используем внешний сигнальный механизм.

Итак, логическое соединение установлено, но еще нет пути, который узлы могли бы использовать для передачи данных. Здесь не все просто, но мы все же можем начать с простых вещей. Представьте, что узлы находятся в одной частной сети. Как мы знаем, они могут легко соединяться друг с другом через свои внутренние IP-адреса (или другие адреса, если TCP/IP не используется).

WebRTC сообщает нам об объектах-кандидатах Ice через некоторые обратные вызовы. Они тоже приходят в виде текста, и их тоже нужно отправить через механизм сигнализации, как и дескрипторы сессии. Если дескриптор сессии содержал информацию о наших настройках на уровне камеры и телефона, то кандидаты делают это с нашим размещением в сети. Отправьте их другому узлу, и он сможет логически соединиться с нами. Поскольку у него уже есть дескриптор сессии, данные будут поступать. Если он не забудет послать нам свой объект-кандидат (информацию о том, где он находится внутри сети), мы сможем соединиться с ним.

Есть еще одно отличие от классического взаимодействия клиент-сервер. Общение с HTTP-сервером происходит по схеме "запрос-ответ". Клиент отправляет данные на сервер, сервер обрабатывает их и отправляет по адресу, указанному в пакете запроса. В WebRTC обязательно нужно знать два адреса и соединять их с обеих сторон.

Отличие от дескрипторов сессий в том, что устанавливать нужно только удаленные кандидаты. Редактирование здесь запрещено и не принесет пользы. В различных реализациях WebRTC кандидаты должны быть установлены только после установки дескрипторов сессии.

Итак, почему может быть один дескриптор сессии, но много кандидатов? Потому что расположение в сети может определяться не только собственным внутренним IP-адресом, но и адресом внешнего маршрутизатора (одного или нескольких), а также адресами TURN-серверов.

Итак, у нас есть два кандидата в пределах одной сети (рисунок ниже). Как их идентифицировать? Только с помощью IP-адресов. Конечно, может использоваться разный транспорт (TCP и UDP), а также разные порты. Именно эта информация содержится внутри объекта-кандидата — IP, TRANSPORT, PORT и т.д. Например, возьмем порт 531 и транспорт UDP.

Итак, когда мы находимся внутри узла p1, WebRTC отправит нам следующее в качестве объекта-кандидата: [10.50.200.5, 531, udp]. Это не точная вещь, просто схема. Если мы находимся внутри узла p2, кандидат изменится на [10.50.150.3, 531, udp]. P1 получит IP и PORT узла p2 через механизм сигнализации и сможет подключиться к p2 напрямую. Фактически, p1 отправит данные на 10.50.150.3:531, надеясь, что они достигнут p2. Принадлежит ли этот адрес p2 или посреднику, не так важно. Важно то, что данные будут отправлены на этот адрес и смогут достичь p2.

Пока узлы находятся в одной сети, все просто, так как у каждого узла есть только один объект-кандидат (свой собственный, который он размещает в сети). Но если узлы находятся в разных сетях, количество кандидатов возрастет в разы.

Давайте рассмотрим более сложный случай. Один узел находится за маршрутизатором (NAT), а второй узел находится в той же сети, что и этот маршрутизатор (например, в Интернете).

У этого случая есть свое решение. Домашний маршрутизатор обычно имеет таблицу NAT. Этот механизм создан для того, чтобы узлы внутри частной сети маршрутизатора могли общаться, например, с веб-сайтами.

Предположим, что веб-сервер подключен к интернету напрямую, то есть у него есть публичный IP. Пусть это будет узел p2. Тогда узел p1 (веб-клиент) посылает запрос на адрес 10.50.200.10. Сначала данные поступают на маршрутизатор r1, а точнее, на его внутренний интерфейс 192.168.0.1. После этого маршрутизатор запоминает адрес источника (p1) и заносит его в таблицу NAT. Затем маршрутизатор меняет адрес источника на свой собственный (p1 -> r1). Затем, используя свой внешний интерфейс, маршрутизатор отправляет данные на веб-сервер p2. Веб-сервер обрабатывает данные, генерирует ответ, который отправляет обратно маршрутизатору. Когда маршрутизатор получает данные, он проверяет таблицу NAT и отправляет данные на узел p1. Маршрутизатор здесь является посредником.

А что, если несколько узлов из внутренней сети посылают запрос во внешнюю сеть? Как маршрутизатор поймет, куда отправить ответ? Эта проблема решается с помощью портов. Когда маршрутизатор заменяет адрес узла своим собственным, он также заменяет порт. Если два узла запрашивают интернет, то маршрутизатор заменяет их исходные порты на разные. Затем, когда пакет от веб-сервера вернется к маршрутизатору, маршрутизатор поймет получателя пакета по порту. Пример приведен ниже.

Возвращаясь к WebRTC и той части, где он использует протокол ICE (следовательно, кандидаты Ice). Узел p2 имеет одного кандидата (его расположение внутри сети, 10.50.200.10), а узел p1, который находится у маршрутизатора с NAT, имеет 2 кандидата: локальный (192.168.0.200) и кандидат маршрутизатора (10.50.200.5). Первый кандидат здесь не очень полезен, однако, он генерируется, поскольку WebRTC ничего не знает об удаленном узле — он может находиться в той же сети или нет. Второй кандидат полезен, и, как мы знаем, порт будет играть важную роль для прохождения через NAT.

Запись в таблице NAT создается только тогда, когда данные покидают внутреннюю сеть. Поэтому узел p1 должен сначала отправить свои данные, и только потом данные от p2 могут достичь p1.

Фактически, оба узла будут находиться за NAT. Чтобы создать запись в таблице NAT каждого маршрутизатора, узлы должны отправить что-то удаленному узлу, но на этот раз ни один из них не сможет достичь другого. Это происходит потому, что узлы не знают своих внешних IP-адресов, а посылать данные на внутренние адреса бессмысленно...

Однако если внешние адреса известны, соединение будет легко установлено. Если первый узел пошлет данные маршрутизатору второго узла, маршрутизатор проигнорирует их, поскольку его таблица NAT в этот момент пуста. Однако маршрутизатор первого узла получил запись в таблице NAT. Теперь, как только 2-й узел отправит данные на маршрутизатор первого узла, маршрутизатор успешно отправит их на 1-й узел. Теперь в таблице NAT 2-го маршрутизатора есть необходимые данные.

Проблема в том, что для того, чтобы узнать внешний IP, нам нужен узел, который находится внутри публичной сети. Чтобы решить эту проблему, используются дополнительные серверы, которые подключены к Интернету напрямую. Они также помогают создавать записи в таблице NAT.

Серверы STUN и TURN

Доступные серверы STUN и TURN должны быть упомянуты при инициализации WebRTC, и с этого момента мы будем называть их ICE-серверами. Если серверы не упомянуты, то подключиться смогут только узлы из той же сети (те, которые подключены к сети без NAT). Важно упомянуть, что сети 3g требуют, чтобы вы использовали серверы TURN для работы.

STUN-сервер — это сервер в интернете, который отправляет обратный адрес (адрес источника узла) обратно. Узел, находящийся за маршрутизатором, связывается с сервером STUN, чтобы обойти NAT. Пакет, пришедший на сервер STUN, содержит адрес источника. Это адрес маршрутизатора, другими словами, внешний адрес нашего узла. Это адрес, который возвращает сервер STUN. Таким образом, узел получает свой внешний IP и порт, что делает его доступным в сети. Затем WebRTC создает дополнительного кандидата с этим адресом (внешний адрес маршрутизатора и порт). Теперь в таблице NAT есть запись, которая пропускает пакеты к нашему узлу, которые отправляются на маршрутизатор через правильный порт.

Пример STUN-сервера: как это работает

STUN-сервер будет называться s1. Маршрутизатор и узел обозначаются как r1 и p1 соответственно. Нам также нужно будет следить за таблицей NAT, пусть это будет r1_nat. В этой таблице обычно много записей от различных узлов подсети — мы не будем их упоминать.

Начнем с пустой r1-nat:

Что такое WebRTC? Объясняем простым языком, image #11

В таблице 4 столбца. В ней каждому столбцу из первых двух (IP, PORT) дана их пара из последних двух (IP, PORT).

P1 посылает пакет на s1. Мы видим четыре интересных поля в таблице внизу, они находятся в заголовке транспортного пакета (TCP или UDP) — IP и PORT источника и приемника. Давайте представим, что это адреса.

Что такое WebRTC? Объясняем простым языком, image #12

P1 отправляет этот пакет на r1. Маршрутизатору потребуется подставить адрес источника Src IP, так как адрес, указанный в пакете, не будет работать для внешней сети. Кроме того, адреса из этого диапазона зарезервированы, и в интернете нет адреса, который бы имел такой адрес. Маршрутизатор заменяет пакет и создает новую запись в r1_nat. Поэтому ему необходимо придумать номер порта. Поскольку различные узлы внутри подсети могут обращаться к внешней сети, таблица NAT должна содержать дополнительную информацию, чтобы маршрутизатор мог определить, какой узел является получателем обратного пакета от сервера. Представим, что маршрутизатор создал порт 888.

Измененный заголовок пакета:

Что такое WebRTC? Объясняем простым языком, image #13

10.50.200.5 — внешний адрес роутера.

r1_nat:

Что такое WebRTC? Объясняем простым языком, image #14

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

Реальный порт, к которому узел p1 принимает соединение, действительно, 35777, но сервер посылает данные на фиктивный порт 888. Позже он будет изменен на настоящий, 35777.

Итак, маршрутизатор подставил в заголовок пакета адрес и порт источника и добавил запись в NAT Теперь пакет отправляется по сети на сервер — на узел s1. На входе S1 имеет такой пакет:

Что такое WebRTC? Объясняем простым языком, image #15

Итак, сервер STUN знает, что он получил пакет от 10.50.200.5:888. Теперь сервер посылает этот адрес обратно. Здесь стоит ненадолго остановиться и посмотреть еще раз.

Таблицы выше — это фрагмент из заголовка пакета, а не из его содержимого. Мы не обсуждали содержимое, поскольку оно не так важно — оно описано в протоколе STUN. Теперь, однако, мы также рассмотрим содержание. Оно будет простым и будет содержать адрес маршрутизатора — 10.50.200.5:888, несмотря на то, что мы взяли его из заголовка пакета. Это делается нечасто, поскольку протоколы обычно не слишком заботятся об адресах узлов. Важно лишь, чтобы пакеты были доставлены по назначению. Но здесь мы рассматриваем протокол, который устанавливает путь между двумя узлами.

Теперь у нас есть 2-й пакет, который идет в обратном направлении:

Что такое WebRTC? Объясняем простым языком, image #16

Заголовок изменился, потому что источник и приемник поменялись местами, что логично, так как место назначения пакета теперь другое.

Что такое WebRTC? Объясняем простым языком, image #17

Это содержимое пакета. На самом деле, он может содержать много информации, но здесь упоминается только то, что важно для понимания работы сервера STUN.

Далее пакет путешествует по сети, пока не оказывается на внешнем интерфейсе r1. Маршрутизатор понимает, что пакет предназначен не для него. Каким образом? Это можно определить по порту. Порт 888 используется маршрутизатором не по своему прямому назначению, а для механизма NAT. Вот почему маршрутизатор смотрит в эту таблицу. Он также смотрит на колонку External PORT и ищет строку, которая совпадает с Dest PORT из прибывшего пакета, то есть 888.

Что такое WebRTC? Объясняем простым языком, image #18

Нам повезло, что этот ряд существует. Если бы не повезло, пакет был бы отброшен. Теперь нам нужно понять, на какой узел подсети отправить пакет. Не спешите, давайте вспомним, насколько важны порты в этом механизме. Два узла подсети могут посылать запросы во внешнюю сеть. Тогда, если маршрутизатор создал порт 888 для первого узла, то для второго он создаст порт 889. Предположим, что это так, и r1_nat выглядит следующим образом:

Что такое WebRTC? Объясняем простым языком, image #19

По порту 888 мы можем понять, что нужный внутренний адрес 192.168.0.200:35777. Маршрутизатор изменяет адрес этого приемника с

Что такое WebRTC? Объясняем простым языком, image #20

на

Что такое WebRTC? Объясняем простым языком, image #21

Пакет успешно достигает узла r1, и, просмотрев содержимое пакета, узел узнает свой внешний IP-адрес — адрес во внешней сети. Он также знает порт, для которого он прокладывает путь через NAT.

Что дальше? Чем это полезно? Полезность заключается в записи в таблицу r1_nat. Если кто-то пошлет пакет с портом 888 на r1, пакет будет перенаправлен на p1. Таким образом, создается узкий путь к скрытому узлу p1.

Из приведенного примера вы можете представить, как работают NAT и STUN-сервер. На самом деле, серверы ICE и STUN/TURN существуют для обхода ограничений NAT.

Между узлом и сервером может быть несколько маршрутизаторов. В этом случае узел будет получать адрес того маршрутизатора, который первым находится в той же сети, что и сервер. Другими словами, мы получим адрес маршрутизатора, который подключен к серверу STUN. Это именно то, что нам нужно для p2p-коммуникации, если иметь в виду тот факт, что для каждого маршрутизатора будет обновляться важная строка в таблице NAT. Поэтому обратный путь будет гладким как шелк.

Сервер TURN — это модернизированный сервер STUN, поэтому каждый сервер TURN может работать как сервер STUN. Однако у сервера TURN есть свои преимущества. Если связь p2p невозможна (в сетях 3g), сервер становится ретранслятором и начинает работать как посредник. Конечно, о p2p в таком случае не может быть и речи, но вне механизма ICE узлы думают, что у них есть прямое взаимодействие.

Когда TURN-сервер является обязательным условием? Почему сервера STUN недостаточно? Потому что существуют различные виды NAT. Они одинаково подменяют IP-адрес и порт, но некоторые из них имеют встроенную защиту от фальсификации. Например, в таблице симметричного NAT хранятся еще два параметра — IP и порт удаленного узла. Пакет из внешней сети проходит через NAT во внутреннюю сеть только в том случае, если адрес и порт источника совпадают с указанными в таблице. Поэтому трюк с сервером STUN не срабатывает В таблице NAT хранится адрес и порт сервера STUN. Когда маршрутизатор получает пакет от собеседника WebRTC, он отбрасывает его, так как считает пакет фальсифицированным. Пакет пришел не от сервера STUN.

Поэтому сервер TURN необходим, когда два собеседника находятся за симметричным NAT (каждый за своим).

А теперь вкратце

Медиапоток

  • Видео- и аудиоданные упакованы в медиапотоки
  • Медиапотоки синхронизируют медиадорожки, из которых они состоят
  • Различные медиапотоки не синхронизируются между собой
  • Медиапотоки могут быть как локальными, так и удаленными. Локальные отвечают за камеру и микрофон, в то время как удаленные получают данные из сети в виде кода
  • Существует два типа медиапотоков: для видео и для аудио.
  • Медиадорожки могут быть включены или выключены
  • Медиадорожки состоят из медиаканалов
  • Медиадорожки синхронизируют медиаканалы, из которых они состоят
  • Медиапотоки и медиадорожки имеют метки, которые помогают отличить их друг от друга.

Дескриптор сессии

  • Дескриптор сессии используется для логического соединения двух узлов в сети.
  • Дескриптор сессии хранит информацию о доступных способах кодирования аудио- и видеоданных
  • WebRTC использует внешний сигнальный механизм. Передача дескрипторов сессий (SDP) становится задачей приложения
  • Механизм логического соединения состоит из двух шагов: предложение и ответ
  • Генерация дескриптора сессии невозможна без использования локального медиапотока с предложением. Она также невозможна без использования удаленного дескриптора сессии с ответом.
  • Полученный дескриптор должен быть передан реализации WebRTC, независимо от того, был ли этот дескриптор получен удаленно или локально от той же реализации WebRTC.
  • Существует также возможность незначительно изменить дескриптор сессии

Кандидаты

  • Ice-кандидат — это адрес узла в сети.
  • Адрес может быть собственным, маршрутизатора или сервера TURN.
  • Существует множество кандидатов
  • Кандидат состоит из IP-адреса, порта и типа транспорта (TCP или UDP).
  • Кандидаты используются для установления физического соединения между двумя узлами в сети
  • Кандидаты должны быть отправлены через механизм сигнализации
  • Только удаленные кандидаты должны передаваться в реализацию WebRTC
  • В некоторых реализациях WebRTC кандидаты могут быть отправлены только после установки дескриптора сессии

STUN/TURN/ICE/NAT

  • NAT — это механизм, который позволяет получить доступ к внешней сети
  • Домашние маршрутизаторы поддерживают специальную таблицу NAT
  • Маршрутизаторы подменяют адреса в пакетах. Адрес источника становится их собственным, если пакет идет во внешнюю сеть, а адрес источника становится адресом узла во внутренней сети, если пакет пришел из внешней сети.
  • NAT использует порты, чтобы обеспечить многоканальный доступ к внешней сети.
  • ICE — это механизм для обхода NAT
  • Серверы STUN и TURN помогают обойти NAT
  • Сервер STUN позволяет создавать обязательные записи в таблице NAT и возвращает адрес внешнего узла
  • Сервер TURN обобщает механизм STUN и делает его постоянно работающим
  • В худших сценариях TURN-сервер используется в качестве ретранслятора, поэтому p2p превращается в соединение клиент-сервер-клиент
  • Технологии