Déjà, avant de regarder la RFC : tu te trompes sur le fonctionnement de TCP.
Chaque paquet est numéroté
Pour commencer, on parle ici de "segment".
Et non, les segment TCP ne sont ni comptés, ni mémorisés, et le TCP èmetteur n'est pas capable de réèmettre un segment. Seules les données peuvent être réémises.
Le N° est codé sur 16bits donc 65535 possibilités.
Pas du tout.
Le numéro de séquence est sur 32 bits, on se dit donc qu'il peut coder des taille jusqu'à 4 Go (ce qui n'est en fait pas vrai).
Le N° reviens donc a 0 tous les 65535. Avec des grandes Rwin, il y a risque d'avoir le même N° de paquet 2 fois.
Le numéro de séquence ne revient jamais "à zéro", parce qu'il n'y a pas de zéro : Seq = 0 est une valeur non distinguée. Oui, vous allez dire : 0 n'est pas distingué, mais Seq = Seq_initial, c'est pas un cas particulier?
Non, ça n'a rien de particulier. En théorie, on ne réutilise jamais des numéros de séquence qui sont en cours de transit. Cela créé donc une limite sur les segments "en vol" : il n'est pas possible d'avoir des segments représentant plus de 4 Go données voyageant en même temps (là on se dit que la limite n'en est pas une, mais ce n'est pas exact).
En fait, c'est plus complexe : les paquets IP peuvent arriver dans le désordre, y compris les réémissions de données TCP, par exemple un cas très simple de paquet qui arrive un peu en retard (je ne représente qu'un demi-TCP, l'envoi de données de A vers B) :
0. B => A [B -> A : Ack (x) ]
B envoie à A un acquittement pour x : les données jusqu'à l'octet x ont été reçues; A reçoit le paquet
1. A => [A -> B : Seq x "blablabla"]
A envoie un paquet à B contenant un segment de données de numéro de séquence x "blablabla" (9 octets venant après la position x); le paquet n'arrive pas
2. B => A [B -> A : Ack (x) ]
B envoie à A un acquittement indiquant qu'il est toujours à la position x (acquittement dupliqué); A reçoit le paquet
3. A => B [A -> B : Seq x "blablabla"]
A réèmet "blablabla" (à la position x); B reçoit le paquet
B ajoute "blablabla" à son tampon de réception, la position du premier octet à lire passe donc à x+9
4. B => A [B -> A : Ack (x+9) ]
B confirme la réception; A reçoit le paquet
5. => B [A -> B : Seq x "blablabla"]
B reçoit le paquet de l'étape 2; la position actuelle étant x+9 > x, le segment est ignoré
Là l'arrivée du paquet est juste un peu en retard; mais en fait elle peut être bien plus en retard.
Quand on écrit x+9, on peut se demander ce qui se passe si x+9 n'est pas une valeur représentable comme numéro de séquence (et d'acquittement correspondant) sur 32 bits. En fait c'est de arithmétique modulaire : on envoi tout simplement x+9 mod 2**32 (en utilisant un
unsigned int en C sur une machine 32 bits, x+9 est automatiquement effectué en arithmétique modulo 2**32). Mais là, on peut se demander ce qui se passe quand on franchit 2**32 - 1, puisqu'en principe, au moins en C :
4294967295U + 9 < 4294967295U (puisque 4294967295 = 2**32-1 et que 2**32-1 + 9 mod 2**32 = 8 < 2**32-1).
C'est que dans ces cas là, il ne faut pas utiliser le < conventionnel, qui commence à 0, mais une comparaison "circulaire"!
AthéismeSur un stade, si vous regardez des coureurs qui font une course, vous arrivez généralement à savoir qui est le premier à tout moment en regardant uniquement une photo instantanée de la course, pourtant vous ne savez pas combien de tours ils ont fait en tout, ils tournent en rond, vous ne pensez jamais que le premier est dernier, même quand le premier vient de repasser la ligne de départ et que les poursuivants sont avant la ligne de part; les poursuivants ont pourtant fait beaucoup de distance après la ligne de départ, presque un tour de stade, et le coureur de tête seulement quelques mètres! Tout simplement,
vous partez du principe qu'aucun coureur ne peut être tellement en avance qu'il talonne ses poursuivants, ayant presque fait un tour en plus. Autrement dit que différence de distance parcourue par chaque coureur de moins d'un demi tour de stade. Si ce n'est pas le cas, et qu'un coureur va beaucoup plus vite qu'un autre au point qu'il arrive à plus d'un demi tour d'avance, vous ne pouvez pas du tout voir sur une photo instantanée s'il est en premier ou en dernier.)
Pour le segment, c'est la même chose : le stade fait une circonférence de 4 Go; il ne faut pas que le numéro de séquence ait fait un demi tour quand le paquet arrive, soit 2 Go d'avance sur le dernier.
La lettre tombée de la sacocheUn problème délicat des réseaux par paquets, comme de la Poste, c'est le risque qu'une lettre tombe de la sacoche du facteur, soit retrouvée un mois plus, sont remise dans le circuit et arrive très, très, très en retard.
Si la lettre n'est pas datée, et que le récepteur suppose qu'elle a à peu près l'age habituel des lettre qu'il reçoit, ça peut poser problème, parce qu'il va en tenir compte comme si elle était récente :
- si la lettre fait référence à une affaire déjà terminée, le receveur va se douter que c'est une anomalie.
- si l'affaire référencée est toujours en négociation, le receveur va tenter d'appliquer ce qui est dans la lettre; si les instructions sembles cohérentes, c'est mauvais.
Avec un paquet en retard, c'est pareil : si le segment fait partie d'une connexion TCP toujours en cours, si le numéro de séquence est cohérent ... l'instruction contenues dans le segment seront appliquées; l'instruction d'un segment TCP est tout simplement "note que les données reçues de cette connexion TCP sont à partir de la position Seq : "blablabla". Et là, paf les données.
En principe un réseau ne doit pas garder des paquets pour les ressortir des plombes plus tard, et le TTL est supposé borner le temps de vie d'un paquet : un paquet TTL de 40 n'est pas censé encore se balader dans 40 secondes. En pratique, de nombreux routeurs négligent cette règle et sont capables de conserver un paquet une durée très longue (plus d'une seconde c'est extrêmement long) sans décrèmenter le TTL. (Bon, aucun routeur ne devrait conserver un paquet IP aussi longtemps, mais c'est une autre histoire : les administrateurs de routeurs ont pris la très mauvaise habitude de mettre des gros tampons qui évite les suppressions de paquets, alors que la suppression est très souhaitable dès que les paquets en attente s'accumulent.)
Pour éviter ce problème, IP ne propose aucun mécanisme particulièrement robuste pour limiter le temps de vie des paquets, ni pour détecter les vieux paquets. De mon point de vue c'est une des quelques grosses faiblesses de conception du protocole IP.
TCP a donc développé l'option d'horodatage pour cela (et pour une autre raison, mesurer précisèment le RTT), mais pour moi c'est le genre de fonctionnalités qui a sa place au niveau IP : le principe de l'horodatage a un sens pour n'importe ordonner dans le temps quel paquet provenant d'un même périphérique.