Signaling Server — è un componente server dell'infrastruttura WebRTC che facilita lo scambio di metadati tra peer per stabilire e terminare una connessione. A differenza del traffico multimediale, la segnalazione può essere trasmessa tramite qualsiasi protocollo — WebSocket, HTTP, XMPP o SIP. Secondo MDN Web Docs, 2024, la segnalazione è un componente obbligatorio di qualsiasi applicazione WebRTC, poiché il protocollo non definisce un metodo specifico per lo scambio di messaggi di segnalazione.
Punti chiave
Signaling Server — è un servizio di rete responsabile del coordinamento del processo di stabilimento di una connessione WebRTC tra due o più peer. Non trasmette dati multimediali (audio, video, dati DataChannel), ma solo le informazioni di controllo necessarie per la scoperta dei peer e la negoziazione dei parametri di connessione. Dopo il corretto stabilimento di un canale P2P, il Signaling Server potrebbe non essere più necessario, ma in alcune architetture rimane per il successivo scambio di segnali (ad esempio, terminazione della chiamata, aggiunta di partecipanti).
L'architettura di segnalazione include tre componenti: Signaling Server, Signal Channel (protocollo di trasporto tra client e server) e API client (solitamente integrata nello stack WebRTC del browser). La specifica WebRTC (W3C, 2024) intenzionalmente non standardizza il protocollo di segnalazione — gli sviluppatori possono scegliere qualsiasi trasporto adatto alla loro applicazione. Questo approccio flessibile consente di utilizzare WebSocket per applicazioni web, XMPP per sistemi di chat o SIP per l'integrazione con infrastrutture di telecomunicazione.
Prima di stabilire una connessione WebRTC, i peer devono scambiare tre tipi di messaggi: descrizioni di sessione (offer e answer), candidati ICE e informazioni di terminazione/modifica della sessione. Il Signaling Server instrada questi messaggi tra i peer utilizzando identificatori di stanza o utente per l'indirizzamento. Il modello standard è creare una “stanza” dove due partecipanti si connettono e il server ritrasmette i messaggi di ciascun partecipante solo al suo interlocutore.
Signaling Server implementa il seguente protocollo tipico di stabilimento della connessione WebRTC. I peer si connettono al server tramite WebSocket (o altro trasporto) e si registrano in una stanza. Il Peer A (iniziatore) crea un'offerta (descrizione SDP del flusso multimediale in uscita) tramite RTCPeerConnection.createOffer(), la imposta come descrizione locale e la invia al Signaling Server. Il server ritrasmette l'offerta al Peer B. Il Peer B riceve l'offerta, la imposta come descrizione remota, crea una risposta tramite createAnswer(), la imposta come descrizione locale e la rinvia tramite il server. Questo processo è chiamato SDP Offer/Answer.
In parallelo con lo scambio SDP, ogni peer raccoglie candidati ICE (host, srflx, relay) e li invia tramite il Signaling Server all'altro peer. Il peer remoto aggiunge i candidati ricevuti tramite RTCPeerConnection.addIceCandidate(). Il processo ICE testa tutte le combinazioni di candidati per trovare un percorso funzionante. Una volta trovato un percorso funzionante (di solito entro 1–5 secondi), il traffico multimediale inizia a fluire direttamente tra i peer e il Signaling Server non partecipa più alla trasmissione dei dati — il suo ruolo termina fino al prossimo evento di controllo (terminazione chiamata, cambio di qualità del flusso).
Per l'indirizzamento dei messaggi, il Signaling Server utilizza un meccanismo di stanze (rooms) o canali. Ogni nuova sessione WebRTC crea una stanza univoca con un identificatore (solitamente UUID). L'iniziatore crea la stanza e attende la connessione del secondo peer. Il secondo peer si unisce alla stanza usando l'ID ricevuto tramite un canale esterno (ad esempio, un link di invito). Il server mantiene una mappa delle stanze, dove ogni ID corrisponde a un elenco di client connessi. Quando il numero di partecipanti raggiunge due, il server inizia a ritrasmettere messaggi di segnalazione tra di loro.
Signaling Server può utilizzare diversi protocolli di trasporto, ciascuno con i propri vantaggi e svantaggi. La scelta del protocollo dipende dal tipo di applicazione, dai vincoli infrastrutturali e dai requisiti di compatibilità. Di seguito sono riportati i protocolli più comuni e le loro caratteristiche.
| Protocollo | Trasporto | Vantaggi | Svantaggi |
|---|---|---|---|
| WebSocket | TCP | Full-duplex, bassa latenza, integrato nei browser | Complessità di scalabilità, blocco proxy |
| HTTP/SSE | TCP | Compatibile con qualsiasi infrastruttura, semplice da implementare | Solo unidirezionale (server-client), richiede polling |
| XMPP | TCP | Standardizzato, supporto autenticazione, estensibile | Eccessivo per scenari semplici, overhead XML |
| SIP | UDP/TCP | Integrazione con infrastruttura VoIP e telefonica | Complesso, non nativo per browser |
| MQTT | TCP | Leggero, funziona in ambienti IoT, publish/subscribe | Richiede un broker, latenza aggiuntiva |
WebSocket è il protocollo più popolare per Signaling Server nelle applicazioni web. Fornisce comunicazione full-duplex, importante per lo scambio asincrono di candidati SDP e ICE, ed è nativamente supportato da tutti i browser moderni tramite l'API WebSocket. Le implementazioni lato server WebSocket sono disponibili su tutte le piattaforme popolari (Node.js, Python, Java, Go). Per applicazioni con milioni di utenti, vengono utilizzate soluzioni WebSocket scalabili basate su Redis Pub/Sub o Kafka per sincronizzare tra le istanze del Signaling Server.
Consideriamo una semplice implementazione di Signaling Server in Node.js utilizzando la libreria ws (WebSocket) e il server HTTP integrato. Il server supporta la registrazione degli utenti, la creazione di stanze e il relay di messaggi tra i partecipanti.
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);
}
Questo Signaling Server implementa la funzionalità di base: connessione a una stanza, relay di messaggi WebRTC (offer, answer, ice-candidate) tra due peer e gestione delle disconnessioni. Il server utilizza una Map per memorizzare le stanze con i client WebSocket connessi. La funzione relayToPeer invia un messaggio a tutti i partecipanti della stanza tranne il mittente. Per la produzione, sarà necessario aggiungere la convalida dei tipi di messaggio, la gestione degli errori di parsing JSON e un meccanismo heartbeat per rilevare le connessioni interrotte.
Sul lato client, il Signaling Server viene integrato tramite l'API WebSocket del browser. Il client stabilisce una connessione con il server, invia una richiesta per unirsi a una stanza, quindi elabora i messaggi WebRTC in arrivo passandoli a RTCPeerConnection tramite setRemoteDescription() e addIceCandidate(). Il codice client invia anche i propri candidati SDP e ICE al server, ottenuti da RTCPeerConnection tramite l'evento onicecandidate e dopo aver creato offer/answer.
Signaling Server trasmette due tipi principali di metadati: SDP (Session Description Protocol) e candidati ICE. SDP descrive i parametri del flusso multimediale — codec, frequenza di campionamento, numero di canali, direzione di trasmissione (sendrecv, sendonly, recvonly, inactive). I candidati ICE contengono indirizzi di rete (locali, ottenuti da STUN, relay da TURN) attraverso i quali un peer può essere raggiunto per la connessione.
SDP è presentato in un formato di testo contenente sezioni di sessione e media. La parte di sessione descrive i parametri generali (ID di sessione, versione, nome), mentre le sezioni media descrivono ogni flusso multimediale (audio, video, DataChannel) con il suo codec, porta e protocollo. I candidati ICE contengono foundation (identificatore di raggruppamento), priorità, indirizzo IP, porta, tipo (host, srflx, relay) e protocollo (UDP, TCP). Ogni candidato include anche un attributo ufrag (frammento di nome utente) che lo collega a uno specifico processo ICE.
Trickle ICE accelera significativamente lo stabilimento della connessione WebRTC. Invece di attendere la raccolta completa di tutti i candidati ICE (che può richiedere 2–10 secondi in reti complesse), ogni candidato viene inviato al Signaling Server immediatamente dopo la scoperta. Il peer remoto riceve il candidato e inizia immediatamente il test di connessione tramite il framework ICE. Ciò riduce il tempo di stabilimento della connessione a 500–1500 ms nella maggior parte dei casi.
Domande frequenti
Signaling Server — è il “coordinatore” prima di una chiamata. Aiuta due dispositivi a trovarsi e a concordare come comunicheranno. Una volta che i dispositivi si sono “conosciuti” e hanno concordato, il server non è più necessario — comunicano direttamente.
WebRTC non definisce un protocollo di segnalazione in modo che gli sviluppatori possano scegliere il trasporto più adatto. Il browser non ha un meccanismo integrato per scoprire altri utenti — questo compito è svolto dal Signaling Server. Agisce come un “postino”, consegnando inviti e impostazioni di connessione tra i partecipanti alla chiamata.
WebSocket — è la scelta ottimale per la maggior parte delle applicazioni web: full-duplex, nativamente supportato dai browser e semplice da implementare. Per l'integrazione con infrastruttura VoIP esistente, scegli SIP. Per applicazioni chat ricche di funzionalità, usa XMPP. Per scenari IoT, usa MQTT.
Per scalare un Signaling Server, utilizza la scalabilità orizzontale con sincronizzazione tramite Redis Pub/Sub o Kafka. Ogni istanza del server gestisce la sua parte di connessioni WebSocket e un bus dati comune viene utilizzato per il routing dei messaggi tra server. Questo approccio consente di gestire milioni di sessioni di segnalazione simultanee.
Il Signaling Server è critico solo durante la fase di stabilimento della connessione. Se il server diventa temporaneamente non disponibile, le chiamate WebRTC attive continuano — il traffico multimediale fluisce direttamente tra i peer. Il problema sorge solo quando si tenta di stabilire una nuova connessione. Per affidabilità, utilizza il clustering dei server e canali di segnalazione di backup.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche