QUIC DataChannels: premières étapes


Les DataChannels basés sur QUIC sont considérés comme une alternative au transport SCTP actuel. Le groupe de travail Google WebRTC les expérimente déjà:


Essayons aussi. Pour ce faire, nous allons créer une application d'une page similaire à l'exemple d'un canal WebRTC pour l'envoi de texte - il s'agit d'un exemple pleinement fonctionnel (sans serveurs de signalisation), qui, de plus, facilitera la comparaison des approches de mise en œuvre de WebRTC DataChannels.

Avant de commencer, rappelons les bases du DataChannel .

En bref sur DataChannel


Les DataChannels de WebRTC permettent aux participants d'échanger des données arbitraires. Ils peuvent être à la fois fiables - ce qui est très utile lors du transfert de fichiers - et peu fiables, ce qui est acceptable pour les informations sur les positions dans les jeux. L'API est une extension de RTCPeerConnection et ressemble à ceci:

 const dc = pc.createDataChannel("some label string"); // ,    – ,   – //    send dc.send("some string"); //    otherPc.addEventListener('datachannel', e => { const channel = e.channel; channel.onmessage = event => { console.log('received', event.data); }); }); 

Sur la page d'exemples WebRTC officielle, il existe des exemples d' envoi de chaînes et de données binaires .

DataChannel utilise SCTP . Il fonctionne en parallèle avec le transport RTP pour les flux audio et vidéo. Contrairement à UDP, qui est couramment utilisé par les flux audio et vidéo, SCTP offre de nombreuses autres fonctionnalités comme des canaux de multiplexage sur une seule connexion ou des modes fiables, partiellement fiables (c'est-à-dire fiables mais désordonnés) et peu fiables.

Google a introduit QUIC en 2012 (pour en savoir plus sur l'historique du protocole et ses nuances, consultez notre autre documentation - note du traducteur). Comme WebRTC, le protocole QUIC a également été pris sous l'aile de l'IETF et est maintenant HTTP / 3 . QUIC a un certain nombre de grandes innovations, telles que: latence réduite, calcul de la bande passante basé sur le contrôle de la congestion, correction directe du retard (FEC) et implémentation dans l'espace utilisateur (au lieu du noyau) pour un roulement plus rapide.

QUIC pourrait être une alternative à RTCP pour WebRTC - comme un transport pour DataChannel. L'expérience actuelle tente d'éviter d'utiliser l'API RTCPeerConnection ( et SDP! ) En utilisant une version distincte du transport ICE. Considérez-le comme une connexion virtuelle qui ajoute un peu de sécurité et beaucoup de parcours NAT .

Dans la vidéo ci-dessous, Ian Swett de l'équipe de mise en réseau Chrome explique ce concept. Et bien que ce discours remonte à plusieurs années, il fournit toujours des informations complémentaires sur le sujet:


Premiers pas avec QUIC


Heureusement, la plupart du code de l'article de 2015 reste pertinent et s'adapte facilement à la nouvelle API. Voyons cela.

Clonez le code d'ici ou essayez-le ici . Veuillez noter que Chrome (la version 73+ est maintenant Canary) doit être exécuté avec des indicateurs spéciaux pour que l'expérience fonctionne localement:

 google-chrome-unstable --enable-blink-features=RTCQuicTransport,RTCIceTransportExtension 

Configuration du transport ICE


La spécification RTCIceTransport est basée sur ORTC, donc la configuration est similaire à l'ancien code:

 const ice1 = new RTCIceTransport(); ice1.onstatechange = function() { console.log('ICE transport 1 state change', ice1.state); }; const ice2 = new RTCIceTransport(); ice2.onstatechange = function() { console.log('ICE transport 2 state change', ice2.state); }; //  ICE- ice1.onicecandidate = function(evt) { console.log('1 -> 2', evt.candidate); if (evt.candidate) { ice2.addRemoteCandidate(evt.candidate); } }; ice2.onicecandidate = function(evt) { console.log('2 -> 1', evt.candidate); if (evt.candidate) { ice1.addRemoteCandidate(evt.candidate); } }; //  ICE- ice1.start(ice2.getLocalParameters(), 'controlling'); ice2.start(ice1.getLocalParameters(), 'controlled'); ice1.gather(iceOptions); ice2.gather(iceOptions); 

Notez que cette API n'a pas RTCIceGatherer, contrairement à ORTC. Parce que nous avons déjà tout ce dont nous avons besoin pour installer le transport ICE.

Configuration du transport QUIC


 const quic1 = new RTCQuicTransport(ice1); quic1.onstatechange = function() { console.log('QUIC transport 1 state change', quic1.state); }; const quic2 = new RTCQuicTransport(ice2); quic2.onstatechange = function() { console.log('QUIC transport 2 state change', quic2.state); }; //     QUIC quic2.addEventListener('quicstream', (e) => { console.log('QUIC transport 2 got a stream', e.stream); receiveStream = e.stream; }); 

Ici, l'expérience s'écarte d'une spécification qui utilise l'authentification basée sur un certificat. Au lieu de cela, la clé publique est utilisée, comme le dit le post Google Developers :
La connexion RTCQuicTransport est configurée avec une clé publique API. Nous ne prévoyons pas actuellement que cette API remplace la validation d'origine. Il sera remplacé par un certificat à distance signalant pour valider les certificats auto-signés - lorsque QUIC commencera à le prendre en charge dans Chromium.
Jusqu'à présent, tout va bien.

QUICStream pour l'envoi et la réception de données


L'utilisation de QUICStream est un peu plus délicate que WebRTC DataChannel. L'API Streams ( voir les détails sur MDN ) créée par le groupe de travail WHATWG a été acceptée mais pas implémentée .

Nous créons sendStream uniquement après que le transport QUIC passe à l'état «connecté» - dans un état différent, cela entraînerait une erreur:

 quic1.onstatechange = function() { console.log('QUIC transport 1 state change', quic1.state); if (quic1.state === 'connected' && !sendStream) { sendStream = quic1.createStream('webrtchacks'); //   createDataChannel. document.getElementById('sendButton').disabled = false; document.getElementById('dataChannelSend').disabled = false; } }; 

Ensuite, nous attachons les gestionnaires au bouton de soumission et au champ de saisie: après avoir cliqué sur le bouton, le texte du champ de saisie est codé dans Uint8Array et écrit dans le flux:

 document.getElementById('sendButton').onclick = () => { const rawData = document.getElementById('dataChannelSend').value; document.getElementById('dataChannelSend').value = ''; //  Uint8Array. ,       TextEncoder. const data = encoder.encode(rawData); sendStream.write({ data, }); }; 

La première entrée déclenchera l'événement onquicstream sur le transport QUIC distant:

 //     QUIC quic2.addEventListener('quicstream', (e) => { console.log('QUIC transport 2 got a stream', e.stream); receiveStream = e.stream; receiveStream.waitForReadable(1) .then(ondata); }); 

... puis nous attendons que les données soient lisibles:
 function ondata() { const buffer = new Uint8Array(receiveStream.readBufferedAmount); const res = receiveStream.readInto(buffer); const data = decoder.decode(buffer); document.getElementById('dataChannelReceive').value = data; receiveStream.waitForReadable(1) .then(ondata); } 

Toutes les données de receiveStream seront lues, décodées en texte et placées dans le champ de sortie. Et donc à chaque fois que des données lisibles apparaissent.

Conclusion et commentaires


J'espère que cet exemple est plus facile à comprendre que le même sur le blog Google . Cette méthode ne convient guère aux connexions P2P, le DataChannel sur SCTP se porte déjà bien pour elles. Cependant, cela peut être une alternative intéressante aux sockets Web avec un serveur QUIC à l'autre extrémité. Jusqu'à ce que cela se produise, vous devez déterminer une manière décente de travailler avec des canaux peu fiables et désordonnés. À mon avis, les suggestions du post susmentionné ressemblent plus à des hacks qu'à des décisions.

On ne sait pas non plus quel retour les développeurs attendent de l'extérieur. "Introduisez déjà la spécification au lieu de sculpter à nouveau les raccourcis, qui resteront avec nous pendant plusieurs années", cela semble trop évident. De plus, l'opinion générale de la communauté a tendance à utiliser les flux WHATWG, ce qui met dans une lumière étrange les développeurs qui demandent de tester leur propre API pour lire les données.

J'aimerais également que SCTP in Chromium ait des fonctionnalités supplémentaires. Par exemple, cette requête sur DataChannel - la mieux notée, soit dit en passant - est restée presque intacte pendant trois ans. Il n'est pas tout à fait clair pourquoi l'accent est mis sur QUIC alors qu'il y a encore des tâches SCTP; cependant, cela ne devrait empêcher personne de tester QUIC et de commenter les résultats.

Commentaire de Voximplant


Un mot à notre chef de file irbisadm :
Pendant longtemps, nos SDK ont été utilisés pour signaler une prise Web. Il s'agit d'une excellente norme éprouvée, mais elle présente certains problèmes. Le premier est TCP. Et TCP n'est pas si bon et rapide sur les réseaux mobiles, et il ne prend pas en charge l'itinérance entre les réseaux. Deuxièmement, il est souvent textuel (il existe également un mode binaire, mais vous le voyez rarement).

Nous avons récemment lancé un test bêta fermé du protocole de signalisation sur le DataChannel. Ce protocole n'est pas non plus sans inconvénients, mais puisqu'il fonctionne dans des réseaux pauvres et en itinérance, il conquiert à première vue. Avez-vous changé de réseau? Pas besoin de recréer la connexion. ICE Restart dans la plupart des cas aidera à trouver une nouvelle façon de gérer le trafic. Mais, comme je l'ai dit, le protocole présente encore des inconvénients: tous les navigateurs ne prennent pas en charge toutes les extensions de protocole, telles que la livraison garantie et la prise en charge de l'ordre des paquets; le protocole ne prend pas non plus en charge gzip pour le mode texte prêt à l'emploi. Mais tous ces problèmes peuvent être résolus du côté de l'application.

Source: https://habr.com/ru/post/fr441168/


All Articles