Раздел 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 #реальное-время #подготовка-к-интервью