43 votes

Chunking WebSocket Transmission

Comme j'utilise plus régulièrement des connexions WebSocket, je me suis intéressé à la façon dont les choses fonctionnent sous le capot. J'ai donc creusé dans les interminables documents de spécification pendant un moment, mais jusqu'à présent, je n'ai pas vraiment pu trouver quoi que ce soit sur les sujets suivants le découpage du flux de transmission lui-même .

Le protocole WebSocket l'appelle cadres de données (qui décrit le flux de données pur, il est donc aussi appelé cadres de non-contrôle ). D'après ce que j'ai compris de la spécification, il n'y a pas de longueur maximale définie ni de valeur MTU (unité de transfert maximale), ce qui signifie qu'une seule trame de données WebSocket peut contenir, selon la spécification ( !), une quantité infinie de données (veuillez me corriger si je me trompe, je suis encore étudiant dans ce domaine).

Après avoir lu ça, j'ai instantanément installé mon petit Nœud Serveur WebSocket. Comme j'ai une forte Ajax (également sur le streaming et Comet), mes attentes étaient à l'origine du genre, " il doit y avoir une sorte de mode interactif pour lire les données pendant qu'elles sont transférées ". Mais je me trompe, n'est-ce pas ?

J'ai commencé petit, avec 4kb de données.

serveur

testSocket.emit( 'data', new Array( 4096 ).join( 'X' ) );

et comme prévu, cela arrive sur le client sous la forme d'un seul flux de données.

client

wsInstance.onmessage = function( data ) {
    console.log( data.length ); // 4095
};

donc j'ai augmenté la charge utile et je m'attendais à nouveau à ce qu'à un moment donné, le côté client onmessage se déclenchera de manière répétée, ce qui aura pour effet de bloquer la transmission. Mais à mon grand étonnement, cela ne s'est jamais produit ( serveur de nœuds testé sur firefox , chrome y safari côté client). Ma plus grosse charge utile était 80 MB

testSocket.emit( 'data', new Array( 1024*1024*80 ).join( 'X' ) );

et ça arrive toujours en un seul gros morceau de données sur le client. Bien sûr, cela prend un certain temps même si vous avez une bonne connexion. Les questions ici sont

  • est-il possible de fragmenter ces flux, comme pour le mode XHR readyState3 ? ?
  • Y a-t-il une limite de taille pour un seul cadre de données ws ? ?
  • Les websockets ne sont-elles pas censées transférer des charges utiles aussi importantes ? (ce qui m'amène à me demander pourquoi il n'y a pas de taille maximale définie).

Il se peut que je regarde encore les WebSockets d'un mauvais œil. Il n'est peut-être pas nécessaire d'envoyer de grandes quantités de données, et il est préférable de fractionner les données de manière logique avant de les envoyer ?

80voto

oberstet Points 7409

Tout d'abord, vous devez faire la différence entre le WebSocket protocole et le WebSocket API sur Navigateurs .

Le protocole WebSocket a une limite de taille de trame de 2^63 octets, mais un message WebSocket peut être composé d'un nombre illimité de trames.

L'API WebSocket dans les navigateurs n'expose pas une API basée sur la trame ou le flux, mais uniquement une API basée sur le message. La charge utile d'un message entrant est toujours entièrement mise en mémoire tampon (dans l'implémentation WebSocket du navigateur) avant d'être fournie à JavaScript.

Les API d'autres mises en œuvre de WebSocket peuvent fournir un accès par trame ou par flux aux charges utiles transférées via le protocole WebSocket. Par exemple, AutobahnPython fait. Vous pouvez en savoir plus en consultant les exemples ici https://github.com/tavendo/AutobahnPython/tree/master/examples/twisted/websocket/streaming .

Divulgation : je suis l'auteur original d'Autobahn et je travaille pour Tavendo.

Plus de considérations :

Tant qu'il n'y a pas d'API frame/streaming dans le navigateur JS WebSocket API, vous ne pouvez recevoir/envoyer que des messages WS complets.

Une seule connexion WebSocket (simple) ne peut pas entrelacer la charge utile de plusieurs messages. Ainsi, si vous utilisez des messages volumineux, ceux-ci sont délivrés dans l'ordre, et vous ne pourrez pas envoyer de petits messages entre eux alors qu'un message volumineux est toujours en cours de transmission.

Une extension WebSocket est prévue (les extensions sont un mécanisme intégré permettant d'étendre le protocole) : le multiplexage WebSocket. Cela permet d'avoir plusieurs connexions WebSocket (logiques) sur une seule connexion TCP sous-jacente, ce qui présente de multiples avantages.

Note également : vous pouvez ouvrir plusieurs connexions WS (sur différents TCP sous-jacents) à un seul serveur cible à partir d'une seule page JS / HTML. hoy .

Note également : vous pouvez faire du "chunking" vous-même dans la couche application : envoyez votre contenu dans des messages WS plus petits et réassemblez-les vous-même.

Je suis d'accord, dans un monde idéal, vous auriez l'API message/frame/streaming dans le navigateur plus le multiplexage WebSocket. Cela donnerait toute la puissance et la commodité.

10voto

CodeCaster Points 38181

RFC 6455 Section 1.1 :

C'est ce que fournit le protocole WebSocket : [...] une alternative à l'interrogation HTTP pour une communication bidirectionnelle. d'une page web à un serveur distant .

Comme indiqué, les WebSockets sont destinées aux communications entre une page web et un serveur. Veuillez noter la différence entre une page web page et une toile navigateur . Les exemples utilisés sont les jeux sur navigateur et les applications de chat, qui échangent de nombreux petits messages.

Si vous voulez envoyer plusieurs Mo dans un seul message, je pense que vous n'utilisez pas les WebSockets de la manière dont ils ont été conçus. Si vous voulez transférer des fichiers, faites-le en utilisant une simple demande Http, avec la réponse suivante Content-Disposition pour permettre au navigateur de télécharger un fichier.

Si vous expliquez pourquoi vous voulez envoyer de si grandes quantités de données, quelqu'un pourra peut-être vous aider à trouver une solution plus élégante que l'utilisation des WebSockets.

Par ailleurs, un client ou un serveur peut refuser les messages trop volumineux (bien que cela ne soit pas explicitement indiqué comment il refusera) :

RFC 6455 Section 10.4 :

Les implémentations qui ont des limitations spécifiques à l'implémentation et/ou à la plate-forme de la taille de la trame ou de la taille totale du message après le réassemblage de plusieurs trames DOIVENT se protéger contre le dépassement de ces limites. dépasser ces limites. (Par exemple, un point d'extrémité malveillant peut essayer de d'épuiser la mémoire de son homologue ou de monter une attaque par déni de service en envoyant une seule grande trame (par exemple, de taille 2**60) ou en envoyant un long flux de petites trames qui font partie d'un message fragmenté. message fragmenté). Une telle implémentation DEVRAIT imposer une limite à la taille des trames et au nombre de trames. et la taille totale du message après réassemblage de plusieurs trames. trames.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X