Signaling Server — е сървърен компонент на WebRTC инфраструктурата, който осигурява обмен на метаданни между пирове за установяване и прекратяване на връзка. За разлика от медийния трафик, сигнализацията може да се предава по всякакъв протокол — WebSocket, HTTP, XMPP или SIP. Според MDN Web Docs, 2024, сигнализацията е задължителен компонент на всяко WebRTC приложение, тъй като протоколът не определя конкретен начин за обмен на сигнални съобщения.
Основни точки
Signaling Server — е мрежова услуга, отговорна за координиране на процеса на установяване на WebRTC връзка между два или повече пира. Той не предава медийни данни (аудио, видео, данни от DataChannel), а само служебна информация, необходима за откриване на пирове и договаряне на параметри на връзката. След успешно установяване на P2P канал, Signaling Server може вече да не е необходим, но в някои архитектури остава за последващ обмен на сигнали (напр. прекратяване на разговор, добавяне на участници).
Архитектурата на сигнализацията включва три компонента: Signaling Server, Signal Channel (транспортен протокол между клиент и сървър) и клиентски API (обикновено вграден в WebRTC стека на браузъра). WebRTC спецификацията (W3C, 2024) умишлено не стандартизира сигналния протокол — разработчиците могат да изберат всеки транспорт, подходящ за тяхното приложение. Това гъвкаво решение позволява използването на WebSocket за уеб приложения, XMPP за чат системи или SIP за интеграция с телекомуникационна инфраструктура.
Преди установяване на WebRTC връзка, пировете трябва да обменят три типа съобщения: session description (offer и answer), ICE candidates и информация за прекратяване/модификация на сесията. Signaling Server маршрутизира тези съобщения между пировете, използвайки идентификатори на стаи или потребители за адресиране. Стандартният модел — създаване на „стая“, към която се свързват двама участници, и сървърът ретранслира съобщения от всеки участник само на неговия събеседник.
Signaling Server имплементира следния типичен протокол за установяване на WebRTC връзка. Пировете се свързват към сървъра чрез WebSocket (или друг транспорт) и се регистрират в стая. Пир A (инициаторът) създава offer (SDP описание на изходящия медиен поток) чрез RTCPeerConnection.createOffer(), задава го като local description и го изпраща на Signaling Server. Сървърът ретранслира offer на пир B. Пир B получава offer, задава го като remote description, създава answer чрез createAnswer(), задава го като local description и го изпраща обратно чрез сървъра. Този процес се нарича SDP Offer/Answer.
Паралелно с обмена на SDP, всеки пир събира ICE candidates (host, srflx, relay) и ги изпраща чрез Signaling Server на другия пир. Отдалеченият пир добавя получените кандидати чрез RTCPeerConnection.addIceCandidate(). ICE процесът проверява всички комбинации от кандидати, за да намери работещ път. След намиране на работещ път (обикновено за 1–5 секунди), медийният трафик започва да се предава директно между пировете и Signaling Server вече не участва в предаването на данни — ролята му приключва до следващото служебно събитие (прекратяване на разговор, промяна на качеството на потока).
За адресиране на съобщения, Signaling Server използва механизъм на стаи (rooms) или канали. Всяка нова WebRTC сесия създава уникална стая с идентификатор (обикновено UUID). Инициаторът създава стая и чака свързване на втория пир. Вторият пир се свързва към стаята чрез ID, получено по външен канал (напр. линк за покана). Сървърът поддържа карта на стаите, където на всеки ID съответства списък от свързани клиенти. Когато броят на участниците достигне два, сървърът започва да ретранслира сигнални съобщения между тях.
Signaling Server може да използва различни транспортни протоколи, всеки със своите предимства и недостатъци. Изборът на протокол зависи от типа приложение, инфраструктурните ограничения и изискванията за съвместимост. По-долу са представени най-често срещаните протоколи и техните характеристики.
| Протокол | Транспорт | Предимства | Недостатъци |
|---|---|---|---|
| WebSocket | TCP | Пълен дуплекс, ниска латентност, вграден в браузърите | Сложност на мащабиране, блокиране от прокси |
| HTTP/SSE | TCP | Съвместимост с всяка инфраструктура, простота на имплементация | Само еднопосочен (сървър-клиент), изисква Polling |
| XMPP | TCP | Стандартизиран, поддръжка на удостоверяване, разширяем | Излишен за прости сценарии, XML натоварване |
| SIP | UDP/TCP | Интеграция с VoIP и телефонна инфраструктура | Сложен, не е естествен за браузъри |
| MQTT | TCP | Лек, работи в IoT среди, publish/subscribe | Изисква брокер, допълнителна латентност |
WebSocket е най-популярният протокол за Signaling Server в уеб приложения. Той осигурява пълнодуплексна комуникация, важна за асинхронен обмен на SDP и ICE кандидати, и се поддържа естествено от всички съвременни браузъри чрез WebSocket API. Сървърната имплементация на WebSocket е достъпна на всички популярни платформи (Node.js, Python, Java, Go). За приложения с милиони потребители се използват мащабируеми WebSocket решения, базирани на Redis Pub/Sub или Kafka за синхронизация между инстанции на Signaling Server.
Нека разгледаме проста имплементация на Signaling Server в Node.js, използвайки библиотеката ws (WebSocket) и вградения HTTP сървър. Сървърът поддържа регистрация на потребители, създаване на стаи и ретранслация на съобщения между участници.
const WebSocket = require("ws");
const server = new WebSocket.Server({ port: 8080 });
const rooms = new Map();
server.on("connection", (ws) => {
ws.roomId = null;
ws.on("message", (data) => {
const msg = JSON.parse(data);
switch (msg.type) {
case "join":
handleJoin(ws, msg.roomId);
break;
case "offer":
case "answer":
case "ice-candidate":
relayToPeer(ws, msg);
break;
case "leave":
handleLeave(ws);
break;
}
});
ws.on("close", () => handleLeave(ws));
});
function handleJoin(ws, roomId) {
if (!rooms.has(roomId)) {
rooms.set(roomId, []);
}
const room = rooms.get(roomId);
room.push(ws);
ws.roomId = roomId;
if (room.length === 2) {
room[0].send(JSON.stringify({ type: "peer-joined" }));
room[1].send(JSON.stringify({ type: "peer-joined" }));
}
}
function relayToPeer(sender, msg) {
const room = rooms.get(sender.roomId);
if (!room) return;
room.forEach(peer => {
if (peer !== sender && peer.readyState === WebSocket.OPEN) {
peer.send(JSON.stringify(msg));
}
});
}
function handleLeave(ws) {
if (!ws.roomId) return;
const room = rooms.get(ws.roomId);
if (!room) return;
const idx = room.indexOf(ws);
if (idx !== -1) room.splice(idx, 1);
if (room.length === 0) rooms.delete(ws.roomId);
}
Този Signaling Server имплементира основна функционалност: свързване към стая, ретранслация на WebRTC съобщения (offer, answer, ice-candidate) между два пира и управление на прекъсвания. Сървърът използва Map за съхранение на стаи със свързани WebSocket клиенти. Функцията relayToPeer изпраща съобщение до всички участници в стаята, с изключение на подателя. За продукционна среда е необходимо добавяне на потвърждение на типовете съобщения, обработка на грешки при парсване на JSON и механизъм heartbeat за откриване на прекъснати връзки.
От страна на клиента, Signaling Server се интегрира чрез WebSocket API на браузъра. Клиентът установява връзка със сървъра, изпраща заявка за присъединяване към стая и след това обработва входящи WebRTC съобщения, предавайки ги на RTCPeerConnection чрез setRemoteDescription() и addIceCandidate(). Клиентският код също изпраща на сървъра своите SDP и ICE кандидати, получени от RTCPeerConnection чрез събития onicecandidate и след създаване на offer/answer.
Signaling Server предава два ключови типа метаданни: SDP (Session Description Protocol) и ICE candidates. SDP описва параметрите на медийния поток — кодеци, честота на дискретизация, брой канали, посока на предаване (sendrecv, sendonly, recvonly, inactive). ICE candidates съдържат мрежови адреси (локални, получени от STUN, релейни от TURN), на които пирът може да бъде достъпен за връзка.
SDP е представен в текстов формат, съдържащ сесии и медийни секции. Сесийната част описва общи параметри (идентификатор на сесия, версия, име), медийните секции — всеки медиен поток (аудио, видео, DataChannel) с неговия кодек, порт и протокол. ICE кандидати съдържат foundation (идентификатор за групиране), priority, IP адрес, порт, тип (host, srflx, relay) и протокол (UDP, TCP). Всеки candidate също включва атрибут ufrag (username fragment), свързващ го с конкретен ICE процес.
Trickle ICE значително ускорява установяването на WebRTC връзка. Вместо да чака пълното събиране на всички ICE кандидати (което може да отнеме 2–10 секунди в сложни мрежи), всеки кандидат се изпраща на Signaling Server веднага след откриване. Отдалеченият пир получава кандидата и незабавно започва проверка на връзката чрез ICE рамката. Това намалява времето за установяване на връзка до 500–1500 ms в повечето случаи.
Често задавани въпроси
Signaling Server — е „координаторът“ преди разговор. Помага на две устройства да се намерят едно друго и да се договорят как ще комуникират. След като устройствата се „опознаят“ и се договорят, сървърът вече не е необходим — те комуникират директно.
WebRTC не определя протокол за сигнализация, за да могат разработчиците да изберат най-подходящия транспорт. Браузърът няма вграден механизъм за откриване на други потребители — тази задача се решава от Signaling Server. Той служи като „пощальон“, предавайки покани и настройки за връзка между участниците в разговор.
WebSocket — оптималният избор за повечето уеб приложения: пълен дуплекс, естествено поддържан от браузърите, лесен за имплементация. За интеграция със съществуваща VoIP инфраструктура изберете SIP. За чат приложения с богати функции — XMPP. За IoT сценарии — MQTT.
За мащабиране на Signaling Server използвайте хоризонтално мащабиране със синхронизация чрез Redis Pub/Sub или Kafka. Всяка сървърна инстанция обработва своя дял от WebSocket връзки, а за междусървърно маршрутизиране на съобщения се използва обща шина за данни. Този подход позволява обработка на милиони едновременни сигнални сесии.
Signaling Server е критичен само на етапа на установяване на връзка. Ако сървърът е временно недостъпен, активните WebRTC разговори продължават — медийният трафик върви директно между пировете. Проблемът възниква само при опит за установяване на нова връзка. За надеждност използвайте клъстеризация на сървъри и резервни канали за сигнализация.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също