Start · Sprachen · JavaScript · Referenz · RTCPeerConnection: datachannel

RTCPeerConnection: datachannel

Ereignis

Wird an eine <code>RTCPeerConnection</code> gesendet, wenn der entfernte Peer mit <code>createDataChannel()</code> einen neuen <code>RTCDataChannel</code> geöffnet hat.

seit JavaScript Baseline: alle modernen Browser (Chrome, Firefox, Kategorie: webapi

Signatur

peerConnection.addEventListener("datachannel", handler)

Beschreibung

Das Ereignis datachannel vom Typ RTCDataChannelEvent wird auf der empfangenden Seite einer WebRTC-Verbindung ausgelöst, sobald der entfernte Peer einen Datenkanal per RTCPeerConnection.createDataChannel() angelegt hat und dieser ausgehandelt wurde. Über die Eigenschaft event.channel erhält man das zugehörige RTCDataChannel-Objekt, mit dem man anschließend Nachrichten senden und empfangen kann.

Einen Handler registriert man entweder mit pc.addEventListener("datachannel", handler) oder über die Eigenschaft pc.ondatachannel = handler. Das Ereignis lässt sich nicht abbrechen und steigt nicht auf (kein Bubbling).

Wichtig: Die Seite, die createDataChannel() selbst aufruft, erhält kein datachannel-Ereignis – sie besitzt den Kanal bereits als Rückgabewert. Auch bei ausgehandelten Kanälen (negotiated: true mit fester id) wird das Ereignis nicht ausgelöst, da beide Seiten den Kanal selbst erzeugen.

Typische Einsatzgebiete sind Peer-to-Peer-Chats, Dateiübertragung, Synchronisation von Spielzuständen oder kollaborativen Editoren mit niedriger Latenz.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "datachannel".
$handler Pflicht (event: RTCDataChannelEvent) => void Callback, der ein RTCDataChannelEvent erhält. Wichtigste Eigenschaft: event.channel (der neue RTCDataChannel).
$options boolean | AddEventListenerOptions false Optionale Listener-Optionen wie once oder signal (zum Entfernen per AbortController).

Rückgabewert

Typ
void
Beschreibung
addEventListener() gibt nichts zurück. Der Handler erhält ein RTCDataChannelEvent mit der Eigenschaft channel.

Beispiele

Eingehenden Datenkanal mit addEventListener empfangen

const pc = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});

pc.addEventListener('datachannel', (event) => {
  const channel = event.channel;
  console.log(`Neuer Kanal: ${channel.label}`);

  channel.addEventListener('open', () => channel.send('Hallo zurück!'));
  channel.addEventListener('message', (e) => {
    console.log('Nachricht empfangen:', e.data);
  });
  channel.addEventListener('close', () => console.log('Kanal geschlossen'));
});
// ... Signalisierung (Offer/Answer, ICE) erfolgt über eigenen Server
Neuer Kanal: chat Nachricht empfangen: Hallo vom Anrufer

Vollständiges lokales Beispiel mit zwei Peers

const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();

// ICE-Kandidaten direkt austauschen (lokal, ohne Server)
caller.onicecandidate = (e) => e.candidate && callee.addIceCandidate(e.candidate);
callee.onicecandidate = (e) => e.candidate && caller.addIceCandidate(e.candidate);

// Empfängerseite: on-Property statt addEventListener
callee.ondatachannel = ({ channel }) => {
  channel.onmessage = (e) => console.log(`[${channel.label}]`, e.data);
};

// Senderseite erzeugt den Kanal
const chat = caller.createDataChannel('chat');
chat.onopen = () => chat.send('Hallo vom Anrufer');

const connect = async () => {
  await caller.setLocalDescription(await caller.createOffer());
  await callee.setRemoteDescription(caller.localDescription);
  await callee.setLocalDescription(await callee.createAnswer());
  await caller.setRemoteDescription(callee.localDescription);
};
connect();
[chat] Hallo vom Anrufer

Mehrere Kanäle nach Label unterscheiden und Listener entfernen

const pc = new RTCPeerConnection();
const controller = new AbortController();

const handlers = {
  chat: (msg) => console.log('Chat:', msg),
  file: (chunk) => console.log('Dateiblock, Bytes:', chunk.byteLength)
};

pc.addEventListener('datachannel', ({ channel }) => {
  if (channel.label === 'file') channel.binaryType = 'arraybuffer';
  const handle = handlers[channel.label];
  if (!handle) {
    channel.close(); // unbekannte Kanäle ablehnen
    return;
  }
  channel.onmessage = (e) => handle(e.data);
}, { signal: controller.signal });

// Später: keine weiteren Kanäle mehr annehmen
const stopAccepting = () => controller.abort();
// Alternativ bei on-Property: pc.ondatachannel = null;

// Wichtig · Fallstricke

  • Nur auf der Gegenseite: Der Peer, der createDataChannel() aufruft, erhält kein datachannel-Ereignis. Bei negotiated: true wird es auf keiner Seite ausgelöst.
  • Handler früh registrieren: Den Listener vor setRemoteDescription() bzw. vor Abschluss der Aushandlung setzen, damit kein Kanal verpasst wird.
  • Kanal ist evtl. noch nicht offen: event.channel.readyState kann "connecting" sein – vor dem ersten send() auf das open-Ereignis warten, sonst wirft send() einen InvalidStateError.
  • Sicherheit: Empfangene Daten stammen von einem fremden Peer und sind nicht vertrauenswürdig. Niemals ungeprüft per innerHTML einfügen (XSS); JSON-Nachrichten validieren und Größen begrenzen.
  • Binärdaten: Standardmäßig ist binaryType "arraybuffer" (in älteren Implementierungen "blob") – bei Bedarf explizit setzen.
  • Kompatibilität: In allen aktuellen Browsern unterstützt; in Node.js nur über Zusatzbibliotheken (z. B. wrtc/node-datachannel).