Курс «Архитектура мессенджера» · Часть 6 · Звонки и реальное время

Раздел 21. Голосовые и видеозвонки как устроен поток

Чем звонок отличается от сообщений; STUN/TURN, WebRTC и почему UDP.

Звонок — это не «сообщение, только длинное». Архитектурно это отдельная подсистема с другими приоритетами, другим путём данных и даже другим сетевым протоколом. Этот раздел — про звонок 1-на-1; групповые и шифрование — в Разделе 22.

Главное отличие: реальное время вместо «доставить рано или поздно»

Сравни две задачи:

  • Сообщения: дискретные, их можно придержать, поставить в очередь, переслать заново. Главное — ничего не потерять, даже ценой задержки (помнишь durability из Раздела 8).
  • Звонок: непрерывный поток звука и видео в реальном времени. Задержка больше ~150–200 миллисекунд уже мешает разговору. И ключевое: потерянный кусочек переслать бессмысленно — пока он дойдёт заново, разговор уже ушёл вперёд.

Отсюда переворот приоритетов: для звонка лучше потерять маленький кусочек звука, чем заморозить разговор ради его восстановления. Для сообщений — ровно наоборот. Это та мысль, на которой держится весь раздел.

Две разные вещи: сигнализация и медиа

В любом звонке есть два совершенно разных потока, и их важно различать:

  • Сигнализация — это установка и управление звонком: «Алиса звонит Бобу», звонок, принять/сбросить, обмен данными для соединения, «положить трубку». Это маленькие редкие управляющие сообщения, и идут они через обычные серверы мессенджера — по той же связи, что мы строили в Частях 1–4.
  • Медиапоток — это сам звук и видео: огромный, непрерывный, в реальном времени. В идеале он идёт напрямую между устройствами, минуя серверы чата. Это совсем другой путь.

Аналогия: сигнализация — это телефонистка, которая соединяет («соединяю вас»); медиапоток — это сам голос, который потом течёт по линии.

Сигнализация (кто звонит, приём/сброс):
    Алиса ──→ серверы мессенджера ──→ Боб

Медиа (голос/видео), идеал — напрямую:
    Алиса ─────────────────────────→ Боб      (напрямую, P2P)

Напрямую или через посредника: NAT, STUN, TURN

Идеал для звонка 1-на-1 — P2P (peer-to-peer — прямое соединение между устройствами): медиа идёт сразу с устройства на устройство, минимальная задержка, без сервера посередине. Мешает этому NAT.

Проблема: NAT

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

Роутер делает NAT (Network Address Translation — «преобразование сетевых адресов»): подменяет внутренний адрес на публичный. Когда устройство шлёт пакет в интернет, роутер ставит в отправителя свой публичный IP и некоторый порт, запоминает это соответствие в таблице, а когда приходит ответ на этот публичный IP и порт — переводит его обратно на нужное внутреннее устройство. Для исходящих соединений всё работает прозрачно.

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

STUN: узнать свой публичный адрес

Первая проблема — устройство не знает, под каким публичным IP и портом оно видно снаружи (их роутер назначает на лету). Это решает STUN (Session Traversal Utilities for NAT).

Устройство отправляет запрос STUN-серверу в открытом интернете. Сервер смотрит, с какого адреса пришёл пакет (а это и есть публичный IP и порт, назначенные роутером), и возвращает его устройству. Теперь устройство знает свой внешний адрес. Оба собеседника делают так и обмениваются адресами через сигнальный канал (серверы мессенджера).

Дальше — пробивание NAT (NAT hole punching). Роутер пропускает входящие пакеты, только если для них уже есть исходящая запись в таблице. Поэтому если оба устройства одновременно отправят пакеты на публичные адреса друг друга, каждый роутер создаст исходящую запись и затем примет встречный пакет как «ответ» на неё. Прямой канал открыт.

TURN: ретранслятор, когда напрямую нельзя

Пробивание срабатывает не всегда. Некоторые NAT (симметричные) назначают для каждого нового адресата отдельный порт, и адрес, полученный через STUN, не совпадает с тем, что нужен собеседнику; строгие файрволы тоже могут блокировать. Тогда прямое соединение не устанавливается.

На этот случай — TURN (Traversal Using Relays around NAT): сервер-ретранслятор с публичным IP, до которого оба устройства гарантированно достучатся (исходящее соединение к публичному серверу проходит всегда). Оба шлют медиа на TURN, а он пересылает его между ними. Работает в любых условиях, но весь трафик идёт через сервер оператора и стоит денег по полосе, поэтому это запасной путь.

1. STUN → узнаём свой публичный IP и порт, пробуем напрямую
2. Получилось:    устройство ──────────────→ устройство    (P2P)
3. Не получилось: устройство ──→ TURN-сервер ──→ устройство (ретранслятор)

ICE и WebRTC

Перебором вариантов «сначала напрямую, потом через TURN» управляет процедура ICE (Interactive Connectivity Establishment — «установление интерактивного соединения»): она собирает все возможные адреса-кандидаты (внутренний, публичный по STUN, ретранслятор TURN), пробует их и выбирает рабочий.

Всё это вместе — ICE, STUN, TURN плюс захват и сжатие звука/видео и шифрование — собрано в стандартную технологию WebRTC (Web Real-Time Communication — «веб-связь в реальном времени»). На ней построены звонки в большинстве мессенджеров (например, у MAX звонки тоже на WebRTC).

Почему другой протокол: UDP, а не TCP

Для постоянной связи в обмене сообщениями мы брали надёжный протокол — TCP (Transmission Control Protocol — «протокол управления передачей»): он пересылает потерянное и гарантирует порядок. Для сообщений это идеально. Но для живого звука — наоборот, потому что пересылка = ожидание, а опоздавший кусочек звука уже не нужен.

Поэтому медиа идёт по UDP (User Datagram Protocol — «протокол пользовательских датаграмм»): быстрый, «выстрелил и забыл», без пересылок и ожидания. Потерялся пакет — и бог с ним.

TCP (сообщения) UDP (звонок)
Потерянное пересылает бросает
Порядок гарантирует не гарантирует
Приоритет надёжность скорость

Короткая формула: лучше потерять 20 миллисекунд звука, чем заморозить звонок ради их восстановления.

Что делают при плохой сети

Чтобы звонок не «замерзал», применяют несколько приёмов:

  • Буфер сглаживания (jitter buffer): пакеты приходят неравномерно, поэтому их на пару миллисекунд придерживают, чтобы воспроизводить плавно. Размен: больше буфер — глаже звук, но выше задержка.
  • Адаптивное качество: сеть просела — на лету снижают разрешение видео и битрейт звука, лишь бы разговор не прервался. Этим занимаются кодеки (codec — программа сжатия и распаковки звука/видео).
  • Маскировка потерь: мелкие пропажи не восстанавливают, а «достраивают» на слух, чтобы их не было заметно.

Вопросы интервьюера (с разбором)

«Чем звонок принципиально отличается от обмена сообщениями?» Образец: «Звонок — это непрерывный поток в реальном времени, где задержка критична, а потерянный кусочек пересылать бессмысленно, он опоздает. Поэтому приоритеты перевёрнуты: для звонка скорость важнее надёжности — лучше потерять немного звука, чем ждать. Для сообщений наоборот: ничего не теряем, даже ценой задержки. Отсюда у звонка другой путь данных и другой сетевой протокол.»

«Как устроен путь медиапотока и что такое STUN/TURN?» Образец: «Я разделяю сигнализацию и медиа. Сигнализация — установка звонка, приём, сброс — идёт через обычные серверы мессенджера. Медиа в идеале идёт напрямую между устройствами (P2P) ради минимальной задержки. Но устройства спрятаны за NAT и напрямую не видят друг друга, поэтому STUN помогает узнать публичный адрес и соединиться напрямую, а TURN — ретранслятор-посредник на случай, когда напрямую не вышло. Всё это обычно даёт WebRTC.»

«Почему для голоса используют UDP, а не TCP?» Образец: «Потому что TCP ради надёжности пересылает потерянное и ждёт — а для живого звука опоздавший пакет уже бесполезен. UDP быстрый и ничего не пересылает: потерялся кусочек — и ладно. Для разговора лучше пропустить двадцать миллисекунд звука, чем заморозить его, восстанавливая. Надёжность здесь сознательно меняют на скорость.»


#мессенджер #звонки #webrtc #stun-turn #udp #реальное-время #подготовка-к-интервью