2. Streams (Flux)
Les flux dans QUIC fournissent une abstraction de flux d'octets ordonnée et légère (Ordered Byte-Stream Abstraction) à une application. Les flux peuvent être unidirectionnels (Unidirectional) ou bidirectionnels (Bidirectional).
Les flux peuvent être créés en envoyant des données. D'autres processus associés à la gestion des flux — terminaison, annulation et gestion du contrôle de flux — sont tous conçus pour imposer des frais généraux minimaux. Par exemple, une seule trame STREAM (Section 19.8) peut ouvrir, transporter des données pour et fermer un flux. Les flux peuvent également avoir une longue durée de vie et peuvent durer toute la durée d'une connexion.
Les flux peuvent être créés par l'un ou l'autre point de terminaison, peuvent envoyer simultanément des données entrelacées avec d'autres flux et peuvent être annulés. QUIC ne fournit aucun moyen d'assurer l'ordonnancement entre les octets sur différents flux.
QUIC permet à un nombre arbitraire de flux de fonctionner simultanément et à une quantité arbitraire de données d'être envoyée sur n'importe quel flux, sous réserve des contraintes de contrôle de flux et des limites de flux ; voir la Section 4.
2.1. Stream Types and Identifiers (Types de flux et identifiants)
Les flux peuvent être unidirectionnels ou bidirectionnels. Les flux unidirectionnels transportent des données dans une direction : de l'initiateur du flux vers son pair. Les flux bidirectionnels permettent l'envoi de données dans les deux directions.
Les flux sont identifiés au sein d'une connexion par une valeur numérique, appelée identifiant de flux (Stream ID). Un identifiant de flux est un entier de 62 bits (0 à 2^62-1) qui est unique pour tous les flux sur une connexion. Les identifiants de flux sont codés en tant qu'entiers de longueur variable ; voir la Section 16. Un point de terminaison QUIC ne doit pas (MUST NOT) réutiliser un identifiant de flux au sein d'une connexion.
Règles d'encodage des identifiants de flux
Le bit le moins significatif (0x01) de l'identifiant de flux identifie l'initiateur du flux :
- Flux initiés par le client : identifiants de flux pairs (bit mis à 0)
- Flux initiés par le serveur : identifiants de flux impairs (bit mis à 1)
Le deuxième bit le moins significatif (0x02) de l'identifiant de flux distingue :
- Flux bidirectionnels : bit mis à 0
- Flux unidirectionnels : bit mis à 1
Tableau des types de flux
Par conséquent, les deux bits les moins significatifs d'un identifiant de flux identifient un flux comme l'un des quatre types, comme résumé dans le Tableau 1 :
| Valeur des bits | Type de flux |
|---|---|
| 0x00 | Flux bidirectionnel initié par le client (Client-Initiated, Bidirectional) |
| 0x01 | Flux bidirectionnel initié par le serveur (Server-Initiated, Bidirectional) |
| 0x02 | Flux unidirectionnel initié par le client (Client-Initiated, Unidirectional) |
| 0x03 | Flux unidirectionnel initié par le serveur (Server-Initiated, Unidirectional) |
Tableau 1 : Types d'identifiants de flux
Règles d'allocation des identifiants de flux
L'espace de flux pour chaque type commence à la valeur minimale (0x00 à 0x03, respectivement) ; les flux successifs de chaque type sont créés avec des identifiants de flux numériquement croissants. Un identifiant de flux utilisé dans le désordre entraîne l'ouverture de tous les flux de ce type avec des identifiants de flux de numérotation inférieure.
2.2. Sending and Receiving Data (Envoi et réception de données)
Les trames STREAM (Section 19.8) encapsulent les données envoyées par une application. Un point de terminaison utilise les champs Stream ID et Offset dans les trames STREAM pour placer les données dans l'ordre.
Les points de terminaison doivent (MUST) être capables de livrer les données de flux à une application sous forme de flux d'octets ordonnés. La livraison d'un flux d'octets ordonnés nécessite qu'un point de terminaison mette en mémoire tampon toutes les données reçues dans le désordre, jusqu'à la limite de contrôle de flux annoncée.
Options de livraison des données
QUIC ne fait aucune disposition spécifique pour la livraison de données de flux dans le désordre. Cependant, les implémentations peuvent (MAY) choisir d'offrir la possibilité de livrer des données dans le désordre à une application réceptrice.
Duplication et cohérence des données
Un point de terminaison peut recevoir des données pour un flux au même décalage de flux plusieurs fois. Les données qui ont déjà été reçues peuvent être rejetées. Les données à un décalage donné ne doivent pas (MUST NOT) changer si elles sont envoyées plusieurs fois ; un point de terminaison peut (MAY) traiter la réception de données différentes au même décalage dans un flux comme une erreur de connexion de type PROTOCOL_VIOLATION.
Limites des trames
Les flux sont une abstraction de flux d'octets ordonnés sans autre structure visible pour QUIC. Les limites des trames STREAM ne sont pas censées être préservées lorsque les données sont transmises, retransmises après une perte de paquet ou livrées à l'application au niveau d'un récepteur.
Contrôle de flux
Un point de terminaison ne doit pas (MUST NOT) envoyer de données sur un flux sans s'assurer qu'elles se situent dans les limites de contrôle de flux définies par son pair. Le contrôle de flux est décrit en détail dans la Section 4.
2.3. Stream Prioritization (Priorisation des flux)
Le multiplexage de flux peut avoir un effet significatif sur les performances de l'application si les ressources allouées aux flux sont correctement hiérarchisées.
QUIC ne fournit pas de mécanisme d'échange d'informations de priorisation. Au lieu de cela, il s'appuie sur la réception d'informations de priorité de l'application.
Une implémentation QUIC devrait (SHOULD) fournir des moyens par lesquels une application peut indiquer la priorité relative des flux. Une implémentation utilise les informations fournies par l'application pour déterminer comment allouer des ressources aux flux actifs.
Explication du mécanisme de priorisation
Différence avec HTTP/2 :
- HTTP/2 définit un arbre de priorités (Priority Tree) au niveau du protocole
- QUIC délègue la décision de priorité à la couche application
- Cela offre plus de flexibilité, mais nécessite que le protocole applicatif conçoive son propre schéma de priorités
2.4. Operations on Streams (Opérations sur les flux)
Ce document ne définit pas d'API pour QUIC ; il définit plutôt un ensemble de fonctions sur les flux sur lesquelles les protocoles d'application peuvent s'appuyer. Un protocole d'application peut supposer qu'une implémentation QUIC fournit une interface qui inclut les opérations décrites dans cette section. Une implémentation conçue pour être utilisée avec un protocole d'application spécifique peut ne fournir que les opérations utilisées par ce protocole.
Opérations côté envoi
Du côté envoi d'un flux, un protocole d'application peut :
Écrire des données (Write Data)
Comprendre quand le crédit de contrôle de flux de flux (Section 4.1) a été réservé avec succès pour envoyer les données écrites
Terminer le flux (End Stream) - Terminaison propre
Entraînant une trame STREAM (Section 19.8) avec le bit FIN défini
Réinitialiser le flux (Reset Stream) - Terminaison abrupte
Entraînant une trame RESET_STREAM (Section 19.4) si le flux n'était pas déjà dans un état terminal
Opérations côté réception
Du côté réception d'un flux, un protocole d'application peut :
Lire des données (Read Data)
Lire les données reçues du flux
Abandonner la lecture (Abort Reading)
Abandonner la lecture du flux et demander la fermeture, entraînant éventuellement une trame STOP_SENDING (Section 19.5)
Notification d'état
Un protocole d'application peut également demander à être informé des changements d'état sur les flux, notamment :
- Lorsque le pair a ouvert ou réinitialisé un flux
- Lorsqu'un pair abandonne la lecture sur un flux
- Lorsque de nouvelles données sont disponibles
- Lorsque des données peuvent ou ne peuvent pas être écrites dans le flux en raison du contrôle de flux
💡 Points clés du mécanisme de flux
Les quatre types de flux
Initié par le client Initié par le serveur
↓ ↓
┌──────────────┐ ┌──────────────┐
│ Bidirectionnel│ (ID: 0,4,8..)│ Bidirectionnel│ (ID: 1,5,9..)
│ 0x00 │ │ 0x01 │
└──────────────┘ └──────────────┘
┌──────────────┐ ┌──────────────┐
│ Unidirectionnel│ (ID: 2,6,10..)│ Unidirectionnel│ (ID: 3,7,11..)
│ 0x02 │ │ 0x03 │
└──────────────┘ └──────────────┘
Cycle de vie d'un flux
Création → Envoi de données → Terminaison/Réinitialisation → Fermeture
↑ ↓
└─ Contrôle de flux ←┘
Caractéristiques clés
- Légèreté : Une seule trame peut ouvrir, transférer et fermer un flux
- Concurrence : Un nombre arbitraire de flux peut être actif simultanément
- Indépendance : Pas de garantie d'ordre entre les flux, évite le blocage en tête de ligne
- Flexibilité : Peut avoir une longue durée de vie ou être de courte durée
Comparaison avec TCP
| Caractéristique | Flux QUIC | TCP |
|---|---|---|
| Multiplexage | ✅ Support natif multi-flux | ❌ Flux d'octets unique |
| Blocage en tête de ligne | ✅ Indépendance au niveau du flux | ❌ Blocage global |
| Surcharge de création de flux | Très faible | N/A |
| Contrôle de priorité | Décidé par la couche application | Aucun |
Chapitre suivant : 3. Stream States (États des flux) - Modèle de machine d'états de flux détaillé