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 l'inoltro dei dati e magari la scalabilità in più data center. In questo scenario, esiste un potenziale per un'alta latenza ed è difficile mantenere privati i dati.

Questi problemi possono essere risolti utilizzando l'API RTCDataChannel di WebRTC per trasferire i dati direttamente da un peer a un altro. Questo articolo illustra le nozioni di base per impostare e utilizzare i canali di dati, nonché i casi d'uso più comuni che si trovano oggi sul web.

Perché scegliere un altro canale di dati?

Sono presenti WebSocket, AJAX e Server Inviato Eventi. Perché abbiamo bisogno di un altro canale di comunicazione? WebSocket è bidirezionale, ma tutte queste tecnologie sono progettate per la comunicazione da o verso un server.

RTCDataChannel ha un approccio diverso:

  • Funziona con l'API RTCPeerConnection, che consente la connettività peer-to-peer. Ciò può comportare una minore latenza, nessun server intermedio e meno "hop".
  • RTCDataChannel utilizza Stream Control Transmission Protocol (SCTP), consentendo la configurazione di distribuzione e ritrasmissione con semantica di consegna configurabile.

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

Avviso: segnalazione, STUN e TURN

WebRTC consente la comunicazione peer-to-peer, ma necessita comunque di server per la segnale che possa scambiare metadati di rete e contenuti multimediali per eseguire il bootstrap di una connessione peer.

WebRTC gestisce i NAT e i firewall con:

  • Il framework ICE per stabilire il miglior percorso di rete possibile tra colleghi.
  • Server STUN per determinare un IP e una porta accessibili pubblicamente per ogni peer.
  • Gira i server in caso di interruzione della connessione diretta ed è necessario l'inoltro dei dati.

Per ulteriori informazioni su come funziona WebRTC con i server per il reporting e il networking, consulta WebRTC nel mondo reale: STUN, TURN e segnalazione.

Le funzionalità

L'API RTCDataChannel supporta un set flessibile di tipi di dati. L'API è progettata per imitare esattamente WebSocket e RTCDataChannel supporta le stringhe e alcuni 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à non affidabile e non ordinata (Analoga a User Datagram Protocol o UDP), in modalità affidabile e ordinata (Analoga al Transmission Control Protocol o TCP) e a modalità parzialmente affidabili:

  • La modalità affidabile e ordinata garantisce la trasmissione dei messaggi e anche l'ordine in cui vengono recapitati. Questo comporta un overhead maggiore, che può comportare un rallentamento della modalità.
  • La modalità non affidabile e non ordinata non garantisce che tutti i messaggi arrivino all'altra parte né dell'ordine in cui arrivano. In questo modo si elimina l'overhead e la modalità funziona molto più velocemente.
  • La modalità affidabilità parziale garantisce la trasmissione dei messaggi in una condizione specifica, ad esempio un timeout di ritrasmissione o un numero massimo di ritrasmissioni. È possibile configurare anche l'ordine dei messaggi.

Le prestazioni per le prime due modalità sono all'incirca le stesse in assenza di perdite di pacchetti. Tuttavia, in modalità affidabile e ordinata, una perdita di un pacchetto causa il blocco degli altri pacchetti dietro al pacchetto, che potrebbe risultare inattivo nel momento in cui viene ritrasmesso e arriva. È ovviamente possibile utilizzare più canali di dati all'interno della stessa app, ognuno con una propria semantica affidabile o inaffidabile.

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

TCPUDPSCTP
AffidabilitàAffidabileNon attendibileConfigurabile
ConsegnaOrdine effettuatoNon ordinatoConfigurabile
TrasmissioneOrientata ai byteOrientato ai messaggiOrientato ai messaggi
Controllo del flussoNo
Controllo della congestioneNo

Ora imparerai a configurare RTCDataChannel per l'utilizzo di una modalità affidabile e ordinata oppure inaffidabile e non ordinata.

Configurazione dei canali di dati

Esistono diverse demo semplici di RTCDataChannel online:

In questi esempi, il browser stabilisce una connessione peer con se stesso, quindi crea un canale di dati e invia un messaggio tramite la connessione peer. Crea quindi un canale dati e invia il messaggio lungo 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 generazione degli indicatori. Successivamente, inserisci un'etichetta per distinguere questo canale dagli altri e una serie 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 prima di avere esito negativo), 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 questi documenti RFC IETF: Stream Control Transmission Protocol e Stream Control Transmission Protocol Partial Reliability Extension.

  • ordered: se il canale dati deve garantire o meno l'ordine
  • maxPacketLifeTime: il tempo massimo per provare a ritrasmettere un messaggio di errore
  • maxRetransmits: numero massimo di tentativi per ritrasmettere un messaggio non riuscito
  • protocol: consente di utilizzare un sottoprotocollo, che fornisce meta-informazioni per l'app
  • negotiated: se impostato su true, rimuove la configurazione automatica di un canale di dati sull'altro peer, offrendoti un modo personale per creare un canale di dati con lo stesso ID sull'altro lato.
  • id: ti consente di fornire un tuo ID per il canale che può essere utilizzato solo in combinazione con l'opzione negotiated impostata su true

Le uniche opzioni di cui 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) l'opzione affidabile e ordinata è true per impostazione predefinita. Ha senso utilizzare soluzioni inaffidabili e non ordinate se vuoi il pieno controllo dal livello dell'app, ma nella maggior parte dei casi l'affidabilità parziale è utile.

Tieni presente che, come con WebSocket, RTCDataChannel attiva gli eventi quando una connessione viene stabilita, chiusa o quando si verifica un errore 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 tramite Datagram Transport Layer Security (DTLS). DTLS è un derivato di SSL, il che significa che i tuoi dati saranno sicuri come qualsiasi connessione standard basata su SSL. DTLS è standardizzato e integrato in tutti i browser che supportano WebRTC. Per ulteriori informazioni, consulta la wiki di Wireshark.

Cambia il tuo modo di pensare ai dati

La gestione di grandi quantità di dati può essere un problema in JavaScript. Come hanno sottolineato gli sviluppatori di Sharefest, questo ha richiesto un approccio nuovo ai dati. Se stai trasferendo un file di dimensioni superiori alla quantità di memoria a tua disposizione, devi pensare a nuovi modi per salvare queste informazioni. È qui che entrano in gioco le tecnologie come l'API FileSystem, come vedremo in seguito.

Crea un'app per la condivisione di file

Con RTCDataChannel ora è possibile creare un'app web in grado di condividere file nel browser. Basandosi su RTCDataChannel significa che i dati dei file trasferiti sono criptati e non toccano i server del fornitore di un'app. Questa funzionalità, combinata con la possibilità di connetterti 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. Crea una connessione peer tra i client con RTCPeerConnection.
  3. Crea un canale dati tra i client con RTCDataChannel.

Quando provi a inviare file di dimensioni superiori a RTCDataChannel, devi valutare diversi aspetti:

  • Dimensioni del file: se le dimensioni del file sono ragionevolmente piccole e possono essere archiviati e caricati come un unico BLOB, puoi caricarlo in memoria utilizzando l'API File e quindi inviare il file su un canale affidabile così com'è (anche se tieni presente che i browser impongono limiti alle dimensioni massime di trasferimento). Man mano che le dimensioni dei file aumentano, le cose si fanno sempre più complicate. Quando è richiesto un meccanismo di chunking, i blocchi di file vengono caricati e inviati a un altro peer, insieme ai metadati chunkID, in modo che il peer possa riconoscerli. Tieni presente che, in questo caso, devi anche salvare i blocchi nell'archiviazione offline (ad esempio, utilizzando l'API FileSystem) e salvarli sul disco dell'utente solo quando hai il file nella sua interezza.
  • Dimensioni maggiori: sono gli "atomi" più piccoli di dati per la tua app. La suddivisione in blocchi è obbligatoria perché esiste attualmente un limite per le dimensioni di invio (anche se questo problema verrà risolto in una versione futura dei canali dati). L'attuale consiglio per la dimensione massima del blocco è 64 KiB.

Dopo aver trasferito completamente il file nell'altro lato, puoi scaricarlo utilizzando un anchor tag:

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. Sono entrambi open source e rappresentano una buona base per un'app di condivisione file basata su RTCDataChannel.

Cosa puoi fare?

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

  • Condivisione di file peer-to-peer come descritto in precedenza
  • Giochi multiplayer con altre tecnologie, come WebGL, che compaiono in BananaBread di Mozilla
  • Distribuzione dei contenuti reinventata da PeerCDN, un framework che fornisce risorse web attraverso la comunicazione dei dati peer-to-peer

Cambia il modo in cui crei le app

Ora puoi fornire app più coinvolgenti utilizzando connessioni a bassa latenza e ad alte prestazioni tramite RTCDataChannel. I framework, come PeerJS e l'SDK WebRTC PubNub, semplificano l'implementazione di RTCDataChannel e l'API dispone ora di un ampio supporto su più piattaforme.

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

Scopri di più