Inviare dati tra browser con canali di dati WebRTC

L'invio di dati tra due browser per la comunicazione, i giochi o il trasferimento di file può essere un processo piuttosto complesso. Richiede la configurazione e il pagamento di un server per il relay dei dati e, forse, il suo scalabilità a più data center. In questo scenario, esiste il potenziale per una latenza elevata ed è difficile mantenere privati i dati.

Questi problemi possono essere alleviati utilizzando l'API RTCDataChannel di WebRTC per trasferire i dati direttamente da un peer all'altro. Questo articolo illustra le nozioni di base su come configurare e utilizzare i canali di dati, nonché i casi d'uso comuni sul web oggi.

Perché un altro canale di dati?

Abbiamo WebSocket, AJAX ed Eventi inviati dal server. Perché abbiamo bisogno di un altro canale di comunicazione? WebSocket è bidirezionale, ma tutte queste tecnologie sono progettate per la comunicazione con o da un server.

RTCDataChannel adotta un approccio diverso:

  • Funziona con l'API RTCPeerConnection, che consente la connettività peer-to-peer. Ciò può comportare una latenza inferiore, nessun server intermedio e meno "hop".
  • RTCDataChannel utilizza lo Stream Control Transmission Protocol (SCTP), che consente la semantica di distribuzione configurabile, la distribuzione non in ordine e la riconfigurazione della trasmissione.

RTCDataChannel è ora disponibile con il supporto SCTP su computer e Android in Google Chrome, Opera e Firefox.

Un avviso: segnalazione, STUN e TURN

WebRTC consente la comunicazione peer-to-peer, ma ha comunque bisogno di server per la segnalazione per scambiare metadati di rete e multimediali per avviare una connessione peer.

WebRTC gestisce NAT e firewall con:

  • Il framework ICE per stabilire il miglior percorso di rete possibile tra i peer.
  • Server STUN per determinare un IP e una porta accessibili pubblicamente per ogni peer.
  • Server TURN se la connessione diretta non va a buon fine ed è necessario il relay dei dati.

Per saperne di più su come funziona WebRTC con i server per la segnalazione e il networking, consulta WebRTC in the real world: STUN, TURN, and signaling.

Le funzionalità

L'API RTCDataChannel supporta un insieme flessibile di tipi di dati. L'API è progettata per imitare esattamente WebSocket e RTCDataChannel supporta le stringhe, nonché alcuni dei tipi binari in JavaScript, come Blob, ArrayBuffer e ArrayBufferView. Questi tipi possono essere utili quando si lavora con il trasferimento di file e i giochi multiplayer.

RTCDataChannel può funzionare in modalità inaffidabile e non ordinata (analoga a User Datagram Protocol o UDP), in modalità affidabile e ordinata (analoga a Transmission Control Protocol o TCP) e in modalità parzialmente affidabili:

  • La modalità affidabile e ordinata garantisce la trasmissione dei messaggi e anche l'ordine in cui vengono consegnati. Ciò comporta un overhead aggiuntivo, rendendo potenzialmente questa modalità più lenta.
  • La modalità non affidabile e non ordinata non garantisce che ogni messaggio arrivi all'altra parte né l'ordine in cui arriva. In questo modo, si elimina il sovraccarico, consentendo a questa modalità di funzionare molto più velocemente.
  • La modalità affidabile parziale garantisce la trasmissione del messaggio in una condizione specifica, ad esempio un timeout di ritrasmissione o un numero massimo di ritrasmissioni. Anche l'ordinamento dei messaggi è configurabile.

Le prestazioni per le prime due modalità sono pressoché identiche in assenza di perdita di pacchetti. Tuttavia, in modalità affidabile e ordinata, un pacchetto perso causa il blocco degli altri pacchetti che lo seguono e il pacchetto perso potrebbe essere obsoleto quando viene ritrasmesso e arriva. Naturalmente, è possibile utilizzare più canali di dati all'interno della stessa app, ognuno con la propria semantica affidabile o inaffidabile.

Ecco una tabella utile tratta da High Performance Browser Networking di Ilya Grigorik:

TCPUDPSCTP
AffidabilitàAffidabileNon attendibileConfigurabile
DeliveryOrderedNon ordinatoConfigurabile
TrasmissioneOrientato ai byteOrientato al messaggioOrientato al messaggio
Controllo del flussoNo
Controllo della congestioneNo

Successivamente, imparerai a configurare RTCDataChannel per utilizzare la modalità affidabile e ordinata o inaffidabile e non ordinata.

Configurare i canali di dati

Esistono diverse demo semplici di RTCDataChannel online:

In questi esempi, il browser stabilisce una connessione peer a se stesso, quindi crea un canale di dati e invia un messaggio tramite la connessione peer. Quindi, crea un canale di dati e invia il messaggio tramite la connessione peer. Infine, il messaggio viene visualizzato nella casella sull'altro lato della pagina.

Il codice per iniziare è breve:

const peerConnection = new RTCPeerConnection();

// Establish your peer connection using your signaling channel here
const dataChannel =
  peerConnection.createDataChannel("myLabel", dataChannelOptions);

dataChannel.onerror = (error) => {
  console.log("Data Channel Error:", error);
};

dataChannel.onmessage = (event) => {
  console.log("Got Data Channel Message:", event.data);
};

dataChannel.onopen = () => {
  dataChannel.send("Hello World!");
};

dataChannel.onclose = () => {
  console.log("The Data Channel is Closed");
};

L'oggetto dataChannel viene creato da una connessione peer già stabilita. Può essere creato prima o dopo la segnalazione. A questo punto, devi inserire un'etichetta per distinguere questo canale dagli altri e un insieme di impostazioni di configurazione facoltative:

const dataChannelOptions = {
  ordered: false, // do not guarantee order
  maxPacketLifeTime: 3000, // in milliseconds
};

È anche possibile aggiungere un'opzione maxRetransmits (il numero di tentativi da effettuare prima di non riuscire), ma puoi specificare solo maxRetransmits o maxPacketLifeTime, non entrambi. Per la semantica UDP, imposta maxRetransmits su 0 e ordered su false. Per ulteriori informazioni, consulta le RFC IETF: Stream Control Transmission Protocol e Stream Control Transmission Protocol Partial Reliability Extension.

  • ordered: indica se il canale di dati deve garantire l'ordine o meno
  • maxPacketLifeTime: il tempo massimo per tentare di ritrasmettere un messaggio non riuscito
  • maxRetransmits: il numero massimo di tentativi di ritrasmissione di un messaggio non riuscito
  • protocol: consente l'utilizzo di un sottoprocollo, che fornisce metadati all'app
  • negotiated: se impostato su true, rimuove la configurazione automatica di un canale di dati sull'altro peer, fornendo un modo personalizzato per creare un canale di dati con lo stesso ID sull'altro lato
  • id: consente di fornire il proprio ID per il canale, che può essere utilizzato solo in combinazione con negotiated impostato su true)

Le uniche opzioni che la maggior parte delle persone deve utilizzare sono le prime tre: ordered, maxPacketLifeTime e maxRetransmits. Con SCTP (ora utilizzato da tutti i browser che supportano WebRTC), affidabile e ordinato è true per impostazione predefinita. È consigliabile utilizzare l'opzione Inaffidabile e non ordinato se vuoi il controllo completo dal livello dell'app, ma nella maggior parte dei casi l'affidabilità parziale è utile.

Tieni presente che, come per WebSocket, RTCDataChannel attiva gli eventi quando una connessione viene stabilita, chiusa o si verificano errori e quando riceve un messaggio dall'altro peer.

È una challenge sicura?

La crittografia è obbligatoria per tutti i componenti WebRTC. Con RTCDataChannel, tutti i dati sono protetti con Datagram Transport Layer Security (DTLS). DTLS è un derivato di SSL, il che significa che i tuoi dati saranno protetti come con qualsiasi connessione standard basata su SSL. DTLS è standardizzato e integrato in tutti i browser che supportano WebRTC. Per saperne di più, consulta la wiki di Wireshark.

Modificare il modo in cui pensi ai dati

La gestione di grandi quantità di dati può essere un punto dolente in JavaScript. Come hanno sottolineato gli sviluppatori di Sharefest, ciò ha richiesto di pensare ai dati in un modo nuovo. Se trasferisci un file più grande della quantità di memoria disponibile, devi trovare nuovi modi per salvare queste informazioni. È qui che entrano in gioco tecnologie come l'API FileSystem, come vedrai di seguito.

Crea un'app di condivisione file

Con RTCDataChannel ora è possibile creare un'app web in grado di condividere file nel browser. Basandosi su RTCDataChannel, i dati dei file trasferiti vengono criptati e non vengono toccati i server di un fornitore di app. Questa funzionalità, combinata con la possibilità di connettersi a più client per una condivisione più rapida, rende la condivisione di file WebRTC un ottimo candidato per il web.

Per eseguire correttamente il trasferimento sono necessari diversi passaggi:

  1. Leggi un file in JavaScript utilizzando l'API File.
  2. Stabilisci una connessione peer tra i client con RTCPeerConnection.
  3. Crea un canale di dati tra i clienti con RTCDataChannel.

Quando provi a inviare file tramite RTCDataChannel, tieni presente quanto segue:

  • Dimensione del file:se la dimensione del file è ragionevolmente piccola e può essere archiviata e caricata come un unico blob, puoi caricarlo in memoria utilizzando l'API File e quindi inviarlo tramite un canale affidabile così com'è (anche se tieni presente che i browser impongono limiti alla dimensione massima del trasferimento). Man mano che le dimensioni del file aumentano, le cose si fanno più complicate. Quando è necessario un meccanismo di suddivisione, i blocchi di file vengono caricati e inviati a un altro peer, accompagnati dai metadati chunkID in modo che il peer possa riconoscerli. Tieni presente che, in questo caso, devi anche salvare prima i chunk nello spazio di archiviazione offline (ad esempio utilizzando l'API FileSystem) e salvarli sul disco dell'utente solo quando hai il file nella sua interezza.
  • Dimensioni dei chunk:si tratta dei più piccoli "atomi" di dati per la tua app. La suddivisione in chunk è necessaria perché attualmente esiste un limite di dimensioni di invio (anche se questo verrà corretto in una versione futura dei canali di dati). L'attuale consiglio per la dimensione massima dei chunk è 64 KiB.

Una volta trasferito completamente il file all'altra parte, è possibile scaricarlo utilizzando un tag di ancoraggio:

function saveFile(blob) {
  const link = document.createElement('a');
  link.href = window.URL.createObjectURL(blob);
  link.download = 'File Name';
  link.click();
};

Queste app di condivisione di file su PubShare e GitHub utilizzano questa tecnica. Entrambi sono open source e forniscono una buona base per un'app di condivisione file basata su RTCDataChannel.

Quindi, cosa puoi fare?

RTCDataChannel apre le porte a nuovi modi per creare app per la condivisione di file, giochi multiplayer e distribuzione di contenuti.

  • Condivisione dei file peer-to-peer come descritto in precedenza
  • Il gioco multiplayer, abbinato ad altre tecnologie come WebGL, come si vede in BananaBread di Mozilla
  • La distribuzione dei contenuti è stata reinventata da PeerCDN, un framework che distribuisce gli asset web tramite la comunicazione di dati peer-to-peer

Cambiare il modo in cui crei le app

Ora puoi fornire app più coinvolgenti utilizzando connessioni ad alte prestazioni e bassa latenza tramite RTCDataChannel. Framework come PeerJS e l'SDK PubNub WebRTC semplificano l'implementazione di RTCDataChannel e l'API è ora ampiamente supportata su tutte le piattaforme.

L'avvento di RTCDataChannel può cambiare il modo in cui pensi al trasferimento dei dati nel browser.

Scopri di più