Signatur
Beschreibung
Mit createDataChannel() legst du auf einer RTCPeerConnection einen bidirektionalen Datenkanal an. Die Daten laufen über SCTP innerhalb der verschlüsselten DTLS-Verbindung direkt zwischen den Peers, also ohne Umweg über einen Server. Typische Einsatzgebiete sind Chats, Dateiübertragung, Spielzustände in Multiplayer-Spielen oder die Synchronisation in Echtzeit-Anwendungen.
Wird der erste Datenkanal auf einer Verbindung angelegt, löst das ein negotiationneeded-Ereignis aus. Das Angebot (Offer) muss also nach dem Anlegen des Kanals erzeugt werden, damit die SDP einen m=application-Abschnitt enthält. Weitere Kanäle nutzen dieselbe SCTP-Verbindung und brauchen keine neue Aushandlung.
Standardmäßig wird der Kanal in-band ausgehandelt: Die Gegenseite erhält ein datachannel-Ereignis mit dem neuen Kanal. Alternativ kannst du mit negotiated: true und einer festen id auf beiden Seiten denselben Kanal out-of-band anlegen, dann wird kein datachannel-Ereignis ausgelöst.
Über die Optionen legst du fest, ob der Kanal zuverlässig und in Reihenfolge überträgt (wie TCP, Standard) oder unzuverlässig und ungeordnet (eher wie UDP). Die unzuverlässige Variante eignet sich für zeitkritische Daten wie Positionsupdates, bei denen veraltete Pakete wertlos sind.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $label Pflicht | string | Lesbarer Name des Kanals, höchstens 65.535 Byte (UTF-8). Er muss nicht eindeutig sein und ist auf der Gegenseite über channel.label lesbar. |
|
| $options | object | {} | Konfigurationsobjekt (RTCDataChannelInit) mit folgenden Feldern:
|
Rückgabewert
RTCDataChannel-Objekt. Anfangs hat es den readyState "connecting". Senden ist erst nach dem open-Ereignis möglich.Beispiele
Datenkanal anlegen und Chat-Nachrichten senden (anrufende Seite)
const pc = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});
// Kanal VOR createOffer() anlegen, damit er in der SDP landet
const chat = pc.createDataChannel('chat');
chat.addEventListener('open', () => {
console.log('Kanal offen:', chat.label);
chat.send(JSON.stringify({ text: 'Hallo!' }));
});
chat.addEventListener('message', (event) => {
console.log('Empfangen:', event.data);
});
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// offer über den eigenen Signalisierungsserver an die Gegenseite schicken
signaling.send({ sdp: pc.localDescription });
Kanal auf der Gegenseite über das datachannel-Ereignis empfangen
const pc = new RTCPeerConnection();
pc.addEventListener('datachannel', (event) => {
const channel = event.channel;
console.log(`Neuer Kanal: ${channel.label}`);
channel.onmessage = ({ data }) => {
const msg = JSON.parse(data);
console.log('Nachricht:', msg.text);
channel.send(JSON.stringify({ text: 'Hallo zurück!' }));
};
});
Unzuverlässiger Kanal für Spielpositionen
// Ungeordnet, keine Neuübertragung: veraltete Positionen sind wertlos
const positions = pc.createDataChannel('positions', {
ordered: false,
maxRetransmits: 0
});
positions.binaryType = 'arraybuffer';
positions.onopen = () => {
setInterval(() => {
const buf = new Float32Array([player.x, player.y]);
positions.send(buf.buffer);
}, 50);
};
Out-of-band ausgehandelter Kanal mit fester ID
// Auf BEIDEN Peers identisch aufrufen – kein datachannel-Ereignis
const control = pc.createDataChannel('control', {
negotiated: true,
id: 0
});
control.onopen = () => console.log('Steuerkanal bereit, id =', control.id);
// Wichtig · Fallstricke
- Reihenfolge beachten: Legst du den ersten Kanal erst nach
createOffer()an, fehlt er in der SDP und es ist eine neue Aushandlung nötig. Am besten reagierst du aufnegotiationneeded. - Senden vor
openwirft einenInvalidStateError. Immer auf dasopen-Ereignis warten oderreadyState === 'open'prüfen. maxPacketLifeTimeundmaxRetransmitsgleichzeitig zu setzen, führt zu einemTypeError. Einlabeloderprotocolüber 65.535 Byte ebenfalls.- Ist die Verbindung geschlossen (
signalingState === 'closed'), wirft die Methode einenInvalidStateError. Eine bereits vergebeneidführt zu einemOperationError. - Nachrichtengröße: Die zuverlässig übertragbare Größe hängt vom Browser ab, siehe
pc.sctp.maxMessageSize. Große Dateien in Blöcke von ca. 16–64 KiB aufteilen und überbufferedAmountbzw.bufferedamountlowden Datenfluss steuern. - Die Übertragung ist über DTLS verschlüsselt. Die Signalisierung (Austausch von SDP und ICE-Kandidaten) musst du aber selbst absichern, z. B. über WSS. Empfangene Daten sind nicht vertrauenswürdig: Nicht ungeprüft per
innerHTMLeinfügen (XSS). - Die Option
prioritywird nicht überall unterstützt. Ältere Optionen wiemaxRetransmitTimesind veraltet.