Daten zwischen Browsern mit WebRTC-Datenkanälen senden

Das Senden von Daten zwischen zwei Browsern zur Kommunikation, zum Spielen oder zur Dateiübertragung kann ein ziemlich aufwendiger Prozess sein. Dazu ist es erforderlich, einen Server zum Weiterleiten von Daten einzurichten und zu bezahlen und ihn möglicherweise auf mehrere Rechenzentren zu skalieren. In diesem Szenario besteht das Potenzial für eine hohe Latenz und es ist schwierig, Daten vertraulich zu behandeln.

Diese Probleme lassen sich durch die Verwendung der RTCDataChannel-API von WebRTC beheben, mit der Daten direkt von einem Peer zum anderen übertragen werden können. In diesem Artikel werden die Grundlagen für die Einrichtung und Verwendung von Datenkanälen sowie die häufigsten Anwendungsfälle im Web behandelt.

Warum ein weiterer Datenchannel?

Wir haben WebSocket, AJAX und Server Sent Events. Warum brauchen wir einen weiteren Kommunikationskanal? WebSocket ist bidirektional, aber alle diese Technologien sind für die Kommunikation mit oder von einem Server konzipiert.

RTCDataChannel verfolgt einen anderen Ansatz:

  • Sie funktioniert mit der RTCPeerConnection API, die Peer-to-Peer-Verbindungen ermöglicht. Das kann zu einer geringeren Latenz führen, da kein Zwischenserver und weniger „Hops“ erforderlich sind.
  • RTCDataChannel verwendet das Stream Control Transmission Protocol (SCTP), das konfigurierbare Zustellsemantiken, die Zustellung in beliebiger Reihenfolge und die Konfiguration der erneuten Übertragung ermöglicht.

RTCDataChannel ist jetzt mit SCTP-Unterstützung für Computer und Android in Google Chrome, Opera und Firefox verfügbar.

Hinweis: Signaling, STUN und TURN

WebRTC ermöglicht die Peer-to-Peer-Kommunikation, benötigt aber weiterhin Server für die Signalisierung, um Medien- und Netzwerkmetadaten auszutauschen und eine Peer-Verbindung herzustellen.

WebRTC kommt mit NATs und Firewalls zurecht, indem:

  • Das ICE-Framework, um den bestmöglichen Netzwerkpfad zwischen Peers zu ermitteln.
  • STUN-Server, um eine öffentlich zugängliche IP-Adresse und einen Port für jeden Peer zu ermitteln.
  • TURN-Server, wenn eine direkte Verbindung fehlschlägt und Daten weitergeleitet werden müssen.

Weitere Informationen zur Funktionsweise von WebRTC mit Servern für Signalisierung und Netzwerk finden Sie unter WebRTC in der Praxis: STUN, TURN und Signalisierung.

Funktionen

Die RTCDataChannel API unterstützt eine flexible Auswahl an Datentypen. Die API ist so konzipiert, dass sie WebSocket genau nachbildet. RTCDataChannel unterstützt sowohl Strings als auch einige der binären Typen in JavaScript, z. B. Blob, ArrayBuffer und ArrayBufferView. Diese Typen können beim Arbeiten mit Dateiübertragung und Multiplayer-Spielen hilfreich sein.

RTCDataChannel kann im unzuverlässigen und ungeordneten Modus (analog zu User Datagram Protocol oder UDP), im zuverlässigen und geordneten Modus (analog zu Transmission Control Protocol oder TCP) und in teilweise zuverlässigen Modi ausgeführt werden:

  • Der zuverlässige und geordnete Modus garantiert die Übertragung von Nachrichten und auch die Reihenfolge, in der sie zugestellt werden. Das verursacht zusätzlichen Aufwand und kann diesen Modus daher verlangsamen.
  • Im unzuverlässigen und ungeordneten Modus wird nicht garantiert, dass jede Nachricht auf der anderen Seite ankommt oder in welcher Reihenfolge sie dort ankommt. Dadurch wird der Overhead reduziert und der Modus kann viel schneller ausgeführt werden.
  • Der teilweise zuverlässige Modus garantiert die Übertragung von Nachrichten unter einer bestimmten Bedingung, z. B. einem Zeitlimit für die erneute Übertragung oder einer maximalen Anzahl von erneuten Übertragungen. Die Reihenfolge der Nachrichten ist ebenfalls konfigurierbar.

Die Leistung der ersten beiden Modi ist ungefähr gleich, wenn keine Paketverluste auftreten. Im zuverlässigen und geordneten Modus führt ein verlorenes Paket jedoch dazu, dass andere Pakete dahinter blockiert werden. Das verlorene Paket ist möglicherweise veraltet, wenn es noch einmal gesendet wird und ankommt. Es ist natürlich möglich, mehrere Datenkanäle in derselben App zu verwenden, die jeweils eine eigene zuverlässige oder unzuverlässige Semantik haben.

Hier ist eine hilfreiche Tabelle aus High Performance Browser Networking von Ilya Grigorik:

TCPUDPSCTP
ZuverlässigkeitZuverlässigUnzuverlässigKonfigurierbar
LieferungBestelltUnsortiertKonfigurierbar
ÜbertragungByteorientiertNachrichtenorientiertNachrichtenorientiert
AblaufsteuerungJaNeinJa
StauvermeidungJaNeinJa

Als Nächstes erfahren Sie, wie Sie RTCDataChannel für die Verwendung des zuverlässigen und geordneten oder des unzuverlässigen und ungeordneten Modus konfigurieren.

Datenkanäle konfigurieren

Es gibt mehrere einfache Demos von RTCDataChannel online:

In diesen Beispielen stellt der Browser eine Peer-Verbindung zu sich selbst her, erstellt dann einen Datenkanal und sendet eine Nachricht über die Peer-Verbindung. Anschließend wird ein Datenkanal erstellt und die Nachricht über die Peer-Verbindung gesendet. Ihre Nachricht wird dann im Feld auf der anderen Seite der Seite angezeigt.

Der Code für den Einstieg ist kurz:

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");
};

Das dataChannel-Objekt wird aus einer bereits bestehenden Peer-Verbindung erstellt. Sie kann vor oder nach der Signalisierung erstellt werden. Anschließend übergeben Sie ein Label, um diesen Channel von anderen zu unterscheiden, und eine Reihe optionaler Konfigurationseinstellungen:

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

Es ist auch möglich, die Option maxRetransmits (die Anzahl der Versuche vor dem Fehlschlagen) hinzuzufügen. Sie können jedoch nur „maxRetransmits“ oder „maxPacketLifeTime“ angeben, nicht beides. Setzen Sie für die UDP-Semantik maxRetransmits auf 0 und ordered auf false. Weitere Informationen finden Sie in den IETF-RFCs Stream Control Transmission Protocol und Stream Control Transmission Protocol Partial Reliability Extension.

  • ordered: Gibt an, ob der Datenchannel die Reihenfolge garantieren soll.
  • maxPacketLifeTime: die maximale Zeit, die versucht wird, eine fehlgeschlagene Nachricht noch einmal zu übertragen
  • maxRetransmits: die maximale Anzahl der Versuche, eine fehlgeschlagene Nachricht noch einmal zu übertragen
  • protocol: Ermöglicht die Verwendung eines Subprotokolls, das Metainformationen für die App bereitstellt.
  • negotiated: Wenn auf „true“ gesetzt, wird die automatische Einrichtung eines Datenkanals auf dem anderen Peer entfernt. So können Sie selbst einen Datenkanal mit derselben ID auf der anderen Seite erstellen.
  • id: Damit können Sie eine eigene ID für den Channel angeben, die nur in Kombination mit negotiated = true verwendet werden kann.

Die meisten Nutzer benötigen nur die ersten drei Optionen: ordered, maxPacketLifeTime und maxRetransmits. Bei SCTP (das jetzt von allen Browsern verwendet wird, die WebRTC unterstützen) ist „reliable“ und „ordered“ standardmäßig „true“. Die Verwendung von „unreliable“ und „unordered“ ist sinnvoll, wenn Sie die vollständige Kontrolle über die App-Ebene haben möchten. In den meisten Fällen ist jedoch eine teilweise Zuverlässigkeit hilfreich.

Wie bei WebSocket löst RTCDataChannel Ereignisse aus, wenn eine Verbindung hergestellt oder geschlossen wird, wenn Fehler auftreten und wenn eine Nachricht vom anderen Peer empfangen wird.

Ist es sicher?

Die Verschlüsselung ist für alle WebRTC-Komponenten obligatorisch. Bei RTCDataChannel werden alle Daten mit Datagram Transport Layer Security (DTLS) geschützt. DTLS ist eine Variante von SSL. Ihre Daten sind also genauso sicher wie bei jeder standardmäßigen SSL-basierten Verbindung. DTLS ist standardisiert und in alle Browser integriert, die WebRTC unterstützen. Weitere Informationen finden Sie im Wireshark-Wiki.

Ihre Denkweise in Bezug auf Daten ändern

Die Verarbeitung großer Datenmengen kann in JavaScript schwierig sein. Wie die Entwickler von Sharefest betonten, erforderte dies ein neues Denken über Daten. Wenn Sie eine Datei übertragen, die größer ist als der verfügbare Speicherplatz, müssen Sie sich überlegen, wie Sie diese Informationen speichern können. Hier kommen Technologien wie die FileSystem API ins Spiel, wie Sie als Nächstes sehen.

Dateifreigabe-App entwickeln

Mit RTCDataChannel können Sie jetzt eine Webanwendung erstellen, mit der Dateien im Browser freigegeben werden können. Wenn Sie RTCDataChannel verwenden, werden die übertragenen Dateidaten verschlüsselt und nicht auf den Servern eines App-Anbieters gespeichert. Diese Funktion in Kombination mit der Möglichkeit, eine Verbindung zu mehreren Clients herzustellen, um Dateien schneller zu teilen, macht die WebRTC-Dateifreigabe zu einer starken Option für das Web.

Für eine erfolgreiche Übertragung sind mehrere Schritte erforderlich:

  1. Lesen Sie eine Datei in JavaScript mit der File API.
  2. Stellen Sie eine Peer-Verbindung zwischen Clients mit RTCPeerConnection her.
  3. Erstellen Sie einen Datenkanal zwischen Clients mit RTCDataChannel.

Beim Senden von Dateien über RTCDataChannel sind einige Punkte zu beachten:

  • Dateigröße:Wenn die Dateigröße relativ gering ist und als ein Blob gespeichert und geladen werden kann, können Sie die Datei mit der File API in den Arbeitsspeicher laden und dann über einen zuverlässigen Kanal senden. Beachten Sie jedoch, dass Browser Beschränkungen für die maximale Übertragungsgröße auferlegen. Je größer die Datei, desto schwieriger wird es. Wenn ein Chunking-Mechanismus erforderlich ist, werden Dateichunks geladen und an einen anderen Peer gesendet. Dabei werden chunkID-Metadaten mitgesendet, damit der Peer sie erkennen kann. In diesem Fall müssen Sie die Chunks zuerst im Offlinespeicher speichern (z. B. mit der FileSystem API) und erst dann auf der Festplatte des Nutzers speichern, wenn Sie die Datei vollständig haben.
  • Blockgröße:Dies sind die kleinsten „Atome“ von Daten für Ihre App. Die Aufteilung in Blöcke ist erforderlich, da derzeit ein Limit für die Sendegröße gilt. Dieses Limit wird jedoch in einer zukünftigen Version von Datenkanälen behoben. Die aktuelle Empfehlung für die maximale Chunk-Größe beträgt 64 KiB.

Sobald die Datei vollständig übertragen wurde, kann sie mit einem Anker-Tag heruntergeladen werden:

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

Diese Dateifreigabe-Apps auf PubShare und GitHub verwenden diese Technik. Beide sind Open Source und bieten eine gute Grundlage für eine Dateifreigabe-App auf Basis von RTCDataChannel.

Was können Sie also tun?

RTCDataChannel eröffnet neue Möglichkeiten, Apps für die Dateifreigabe, Multiplayer-Spiele und die Bereitstellung von Inhalten zu entwickeln.

  • Peer-to-Peer-Dateifreigabe wie oben beschrieben
  • Mehrspieler-Gaming in Kombination mit anderen Technologien wie WebGL, wie im BananaBread von Mozilla zu sehen
  • Content-Bereitstellung, die von PeerCDN neu erfunden wurde, einem Framework, das Web-Assets über Peer-to-Peer-Datenkommunikation bereitstellt

Apps anders entwickeln

Mit leistungsstarken Verbindungen mit niedriger Latenz über RTCDataChannel können Sie jetzt ansprechendere Apps anbieten. Frameworks wie PeerJS und das PubNub WebRTC SDK erleichtern die Implementierung von RTCDataChannel und die API wird jetzt auf vielen Plattformen unterstützt.

Die Einführung von RTCDataChannel kann die Art und Weise verändern, wie Sie über die Datenübertragung im Browser denken.

Weitere Informationen