WebRTC

Peer-to-peer соединение между браузерами: видео, аудио, произвольные данные через RTCDataChannel.

Что это

Real-Time Communication. Прямое UDP-соединение между двумя клиентами в обход сервера для самой передачи (сервер нужен только для discovery — сигнальный сервер). Три кита: RTCPeerConnection (само соединение), MediaStream (медиа из камеры/микрофона через getUserMedia), RTCDataChannel (произвольные данные).

Базовое использование

// 1. Создаём peer connection с STUN-серверами (для обнаружения внешнего IP)
const pc = new RTCPeerConnection({
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' },
  ],
});

// 2. DataChannel (например для чата) — инициатор создаёт
const channel = pc.createDataChannel('chat');
channel.onmessage = (e) => console.log('peer:', e.data);
channel.onopen = () => channel.send('hello');

// 3. ICE-кандидаты (адреса) — отдаём другой стороне через сигнальный сервер
pc.onicecandidate = (e) => {
  if (e.candidate) signaling.send({ type: 'ice', candidate: e.candidate });
};

// 4. SDP-offer создаёт инициатор
const offer = await pc.createOffer;
await pc.setLocalDescription(offer);
signaling.send({ type: 'offer', sdp: offer });

// На стороне ответчика:
await pc.setRemoteDescription(offer);
const answer = await pc.createAnswer;
await pc.setLocalDescription(answer);
signaling.send({ type: 'answer', sdp: answer });

// Обратно на стороне инициатора:
await pc.setRemoteDescription(answer);
// Обмен ICE-кандидатами по пути:
pc.addIceCandidate(candidateFromPeer);

// 5. После handshake — channel открыт, можно отправлять
channel.send('текст');
channel.send(new Uint8Array([1, 2, 3]));

Медиа (видеозвонок)

const stream = await navigator.mediaDevices.getUserMedia({
  video: true, audio: true,
});
stream.getTracks.forEach((track) => pc.addTrack(track, stream));

pc.ontrack = (e) => {
  remoteVideo.srcObject = e.streams[0];
};

Архитектура

[Browser A] ──signaling (WS/HTTP)── [Signaling Server] ──signaling── [Browser B]
     │                                                                    │
     └──────────── ICE/STUN handshake через STUN server ──────────────────┘
     │                                                                    │
     └──────── P2P data/media (UDP, прямой канал) ────────────────────────┘
  • Signaling server — твой код (WebSocket-сервер), который пересылает SDP offer/answer и ICE-кандидатов между пирами
  • STUN server — узнаёт публичный IP клиента за NAT (stun.l.google.com:19302 — public Google)
  • TURN server — relay-сервер для случаев когда NAT непрорывается (коммерческий, дорого)

Поддержка

Все современные браузеры. На iOS Safari — есть, с особенностями (медиа-разрешения).

Подводные камни

  • Сигналинг нужен ВСЕГДА — без сервера для обмена SDP пиры не найдут друг друга
  • ICE-handshake может занять секунды
  • За симметричным NAT (корпоративные сети) без TURN не пробьёшься
  • DataChannel ordered/reliable по умолчанию — настраивается через опции в createDataChannel
  • Большие файлы лучше резать на чанки (~16KB) — иначе bufferedAmount забивает
  • В одном RTCPeerConnection может быть много DataChannel'ов

Используется в bootcamp

  • Не в текущих задачах bootcamp напрямую, но один из главных Web API для real-time приложений (P2P чаты, видеозвонки, multiplayer games)

Ссылки

🎓 Источники

См. также