Inviare dati tra browser con canali di dati WebRTC

L'invio di dati tra due browser per comunicazione, giochi o trasferimento di file può essere un processo piuttosto complicato. Richiede la configurazione e il pagamento di un server per il trasferimento dei dati e, eventualmente, la scalabilità a più data center. In questo scenario, è possibile che si verifichino latenze elevate ed è difficile mantenere privati i dati.

Questi problemi possono essere attenuati 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 più comuni sul web oggi.

Perché un altro canale di dati?

Abbiamo WebSocket, AJAX e Server Sent Events. Perché abbiamo bisogno di un altro canale di comunicazione? WebSocket è bidirezionale, ma tutte queste tecnologie sono progettate per la comunicazione verso 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 il protocollo Stream Control Transmission Protocol (SCTP), che consente la configurazione della trasmissione e della ritrasmissione con semantica di invio configurabile e fuori sequenza.

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

Avvertenza: segnalazione, STUN e TURN

WebRTC consente la comunicazione peer-to-peer, ma ha comunque bisogno di server per la segnalazione dello scambio di metadati di rete e multimediali per il bootstrap di una connessione peer.

WebRTC gestisce NAT e firewall con:

  • Il framework ICE per stabilire il miglior percorso di rete possibile tra colleghi.
  • Server STUN per verificare un IP e una porta accessibili pubblicamente per ogni peer.
  • Server TURN in caso di problemi di connessione diretta ed è necessario l'inoltro di dati.

Per saperne di più sul funzionamento di WebRTC con i server per la segnalazione e il networking, consulta l'articolo WebRTC nel mondo reale: STUN, TURN e segnalazioni.

Le funzionalità

L'API RTCDataChannel supporta un insieme flessibile di tipi di dati. L'API è progettata per simulare esattamente WebSocket e RTCDataChannel supporta le stringhe e alcuni tipi binari in JavaScript, ad esempio 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 a Transmission Control Protocol o TCP) e in modalità affidabili parziali:

  • La modalità affidabile e ordinata garantisce la trasmissione dei messaggi e anche l'ordine in cui vengono recapitati. Ciò comporta un overhead aggiuntivo, che potrebbe rendere 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, viene rimosso il sovraccarico, consentendo a questa modalità di funzionare molto più velocemente.
  • La modalità attendibile 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 delle prime due modalità sono circa le stesse quando non si verificano perdite di pacchetti. Tuttavia, in modalità affidabile e ordinata, un pacchetto perso causa il blocco di altri pacchetti e il pacchetto perso potrebbe essere obsoleto al momento della sua ritrasmissione e dell'arrivo. È ovviamente possibile utilizzare più canali di dati all'interno della stessa app, ciascuno con la propria semantica attendibile o non attendibile.

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

TCPUDPSCTP
AffidabilitàAffidabileNon attendibileConfigurabile
DeliveryOrderedNon ordinatiConfigurabile
TrasmissioneOrientata ai byteOrientata ai messaggiOrientata ai messaggi
Controllo del flussoNo
Controllo della congestioneNo

Successivamente, scoprirai come configurare RTCDataChannel per utilizzare la modalità affidabile e ordinata o non affidabile e non ordinata.

Configurazione dei canali di dati

Esistono diverse dimostrazioni semplici di RTCDataChannel online:

In questi esempi, il browser esegue una connessione peer con 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 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 l'invio dell'indicatore. Poi, specifica 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 volte da provare prima del fallimento), ma puoi specificare solo maxRetransmits o maxPacketLifeTime, non entrambe. Per la semantica UDP, imposta maxRetransmits su 0 e ordered su false. Per ulteriori informazioni, consulta queste RFC IETF: Stream Control Transmission Protocol ed Stream Control Transmission Protocol Partial Reliability Extension.

  • ordered: 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 volte per tentare di ritrasmettere un messaggio non riuscito
  • protocol: consente di utilizzare un sottoprotocollo che fornisce metadati all'app
  • negotiated: se impostato su true, rimuove la configurazione automatica di un canale dati sull'altro peer, fornendo un modo per creare un canale dati con lo stesso ID sull'altro lato
  • id: ti consente di fornire il tuo ID canale, che può essere utilizzato solo in combinazione con negotiated impostato su true.

Le uniche opzioni che la maggior parte degli utenti 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. Ha senso utilizzare non attendibili e non ordinati se vuoi il controllo completo dal livello dell'app, ma nella maggior parte dei casi è utile un'affidabilità parziale.

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

Modificare il modo in cui pensi 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 di ripensare ai dati in modo nuovo. Se stai trasferendo un file più grande della memoria disponibile, devi pensare a nuovi modi per salvare queste informazioni. È qui che entrano in gioco tecnologie come l'API FileSystem, come vedrai di seguito.

Creare un'app di condivisione di file

Con RTCDataChannel ora è possibile creare un'app web in grado di condividere file nel browser. Se utilizzi RTCDataChannel come base, 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 una valida candidata per il web.

Per effettuare un trasferimento corretto, 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 di dati tra i clienti con RTCDataChannel.

Esistono diversi aspetti da considerare quando si tenta di inviare file tramite RTCDataChannel:

  • Dimensioni del file: se le dimensioni del file sono ragionevolmente ridotte e possono essere archiviate e caricate come un unico blob, puoi caricarle in memoria utilizzando l'API File e poi inviare il file così com'è tramite un canale affidabile (anche se tieni presente che i browser impongono limiti alle dimensioni massime del trasferimento). Man mano che le dimensioni del file aumentano, le cose si complicano. Quando è necessario un meccanismo di suddivisione in blocchi, 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 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.
  • Dimensione del chunk: si tratta dei più piccoli "atomi" di dati per la tua app. Il chunking è necessario perché al momento esiste un limite di dimensione di invio (anche se questo verrà risolto in una versione futura dei canali di dati). Il consiglio attuale per la dimensione massima del chunk è 64 KB.

Una volta che il file è stato completamente trasferito all'altro lato, può essere scaricato 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 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.

Cosa puoi fare?

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

  • Condivisione di file peer-to-peer come descritto in precedenza
  • Giochi multiplayer, abbinati ad altre tecnologie, come WebGL, come nel caso di BananaBread di Mozilla
  • Distribuzione dei contenuti come reinventato da PeerCDN, un framework che fornisce risorse web tramite una comunicazione di dati peer-to-peer

Modificare il modo in cui crei le app

Ora puoi offrire app più coinvolgenti utilizzando connessioni ad alte prestazioni e a bassa latenza tramite RTCDataChannel. Framework come PeerJS e l'SDK PubNub WebRTC semplificano l'implementazione di RTCDataChannel e l'API ora ha un'ampia compatibilità su più piattaforme.

L'avvento del RTCDataChannel può cambiare la tua idea di trasferimento di dati nel browser.

Scopri di più