Rappelons tout d'abord que dans TCP les indications de quantité de données sont exprimées en un nombre d'octets, parce que
TCP transmet des octets (pas des bits, des quadruplets, des mots). La
Receive Window est une quantité de données donc un nombre d'octets.
La
Receive Window effectue le contrôle de flux de TCP afin qu'un récepteur lent (ou puissant mais débordé!) ne soit pas saturé par les données reçues. Cette valeur correspond à la quantité de données que le récepteur croit pouvoir accepter dans l'immédiat. Le terme de contrôle de flux doit être pris avec des pincettes parce qu'il ne s'agit pas d'un port série où les données doivent être prises en compte impérativement pour ne pas être perdues : l'èmetteur TCP doit de toute façon garder toutes les données envoyées dont il ne sait pas qu'elles ont été reçues. Un récepteur qui annoncerait une RWin large mais qui se retrouverait saturé n'aurait qu'à ignorer les segments TCP qu'il ne sait pas gérer et l'envoyeur les retransmettrait plus lentement, en fonction de la RWin réduite annoncée.
La RWin n'est donc pas une garantie formelle de pouvoir accepter des données (heureusement), mais tout récepteur qui aurait la RWin plus gros que le ventre aurait une performance médiocre puisque l'envoyeur essaierait de saturer le récepteur en permanence.
Précisons qu'historiquement la RWin est un entier positif x codé sur 16 bits, donc limité à 64 Ko. Il n'était pas question de changer la taille du champ (donc réorganiser l'entête TCP, donc faire un TCPv2 à la place de TCPv1, comme IPv6 à la place d'IPv4) juste pour changer ça : il fallait ruser un peu pour faire rentrer plus de bits dans le formalisme de l'entête TCP, tout en maintenant la plus grande compatibilité possible : le code de TCP ne sait pas
a priori si celui qui est en face est une implèmentation historique ou moderne de TCP.
Heureusement les concepteurs de TCP savaient bien dès le départ que le protocole serait perfectionné et ils ont prévu un mécanisme d'extension :
les options TCP. Les options ne doivent servir qu'à des extensions qui ne sont pas obligatoires pour communiquer, sinon on aurait meilleur compte de définir un TCPv2 entièrement nouveau. (IP dispose aussi d'un tel système d'extensions optionnelles.)
Il faut donc que l'entête TCP soit compréhensible par une implèmentation historique qui regarde juste le champ RWin de 16 bits. Il faut donc (à peu près) conserver de sens ce champ.
Par ailleurs, si la possibilité de rajouter des informations par des options est précieuse,
il ne faut pas non plus gaspiller la place disponible dans un paquet TCP avec une tripoté d'options encombrantes : le but est d'améliorer les performances pas de les diminuer. La possibilité de définir une option TCP "RWin vraie" codée sur plus de 16 bits qui supplanterait la RWin sur 16 bits de l'entête n'a pas été retenue, sans doute pour cette raison.
On peut remarquer que la possibilité d'indiquer une RWin de 1534111 octets exactement n'a aucun sens puisque la RWin est juste une estimation de la capacité de traitement future et pas une garantie sur la taille d'une zone mémoire réservée, donc la résolution de l'indication de la RWin n'a pas besoin d'être à l'octet près : il faut juste
une précision relative correcte.
La RWin en octets peut maintenant être codée comme
RWin = x * 2**y
c'est à dire un entier multiplié par une puissance de 2.
x est codé par la RWin historique de l'entête TCP.
y est indiqué par une option TCP transmise par le récepteur TCP lors de l'ouverture de la connexion, appelé
Window ScalingLes contraintes sont donc :
1) pour un récepteur TCP
x est variable mais
y est une constante2) de plus pour un TCP envoyeur historique qui ne comprend pas cette option TCP, RWin =
xIl faut donc dans ces contraintes choisir
a priori une bonne valeur pour
y avant qu'un seul octet soit transmis dans le TCP. Si dès que la RWin est plus grande que
gRWin, on veut qu'un TCP envoyeur historique reçoive l'indication de RWin d'au moins
hRWin (
x >=
hRWin), alors il faut limiter la valeur de
y à log2 (
gRWin /
hRWin) ce qui limite la RWin annoncée (pour un envoyeur TCP moderne) à
x * 2**
y avec
x = 64 K
et
y = log2 (
gRWin /
hRWin)
soit RWin < 64 K * 2**log2 (
gRWin /
hRWin) = 64 K *
gRWin /
hRWinSi on veut une performance optimale avec une implèmentation historique dès que la RWin dépasse
gRWin, alors (
hRWin = 64 Ko) on limite la RWin réelle à
gRWin.
Si on suppose que la RWin va rarement baisser significativement, on peut prendre
gRWin très grand, et donc avoir une bonne performance dans tous les cas.