si un paquet TCP a été partiellement reconnu, comment réagira le mécanisme de retransmission?

12

si un client TCP envoie un paquet, avec un numéro de séquence de 10000 à 20000, à un serveur TCP. le TCP répondra avec un ACK avec seq_ack 20001.

si j'intercepte le paquet TCP du client, et divise le paquet en 2 segments TCP, un avec seq de 10000 à 15000, et l'autre avec seq de 15001 à 20000. Et puis ces 2 segments TCP sont envoyés au serveur TCP. Supposons que le deuxième segment soit perdu dans le chemin. Le serveur TCP répondra un ACK avec seq_ack 15001.

Maintenant, puisque le client TCP envoie un paquet intégral avec seq 10000 à 20000, mais il obtient un ACK avec 15001, du point de vue du client, c'est bizarre. Comment va-t-il réagir? En théorie, le client devrait retransmettre les octets de seq 15001 à 20000, à savoir, le client transmettra de nouveaux paquets de seq 15001. Mais qu'en est-il de la pratique, dans la mise en œuvre de la pile TCP, est-ce la même que dans la théorie?

Je pense que dans le tampon d'envoi TCP, lorsqu'un segment TCP est envoyé, le segment reste là jusqu'à l'ACK. Lorsque l'ACK arrive, ces octets pour le segment sont effacés de la mémoire tampon. Il y a un pointeur dans le tampon d'envoi, quand un ACK arrive, le pointeur pointe vers l'emplacement auquel correspond ack_seq. Les octets situés en dessous de ack_seq sont effacés. De cette façon, l'ensemble du segment n'a pas besoin d'être retransmis?

misteryes
la source

Réponses:

8

Ceci est appelé accusé de réception sélectif et est déjà inclus dans la spécification TCP définie dans RFC 2018 . Cela permettrait au client de ne renvoyer en effet que les octets 15001 à 20000 (car ils se trouvent dans différents paquets / segments si vous les aviez divisés comme vous le dites), mais plus intéressant, cela permet même des accusés de réception hors service.

De RFC 2018:

Lors de la réception d'un ACK contenant une option SACK, l'expéditeur de données DEVRAIT enregistrer l'accusé de réception sélectif pour référence future. L'expéditeur de données est supposé avoir une file d'attente de retransmission qui contient les segments qui ont été transmis mais pas encore acquittés, dans l'ordre des numéros de séquence.

La prise en charge SACKn'est pas requise par la spécification TCP. Si le client ou le serveur ne prenaient pas en charge l'acquittement sélectif, tous les octets 10000 à 20000 devraient en effet être retransmis.

Dans l'implémentation de la pile TCP, est-ce la même chose que dans la théorie?

Il SACK est généralement pris en charge, car les gains de performances, d'efficacité et de latence sont importants, en particulier dans un réseau comme Internet.

En effet, cependant, ces hypothèses devraient rester vraies même si vous manipulez manuellement les paquets comme vous l'avez indiqué. Selon RFC 793 , au minimum, la totalité de la fenêtre de données devra être réémis, mais le recepteur ne sait que les données recus est au moins valide . Pour les détails d'implémentation, Section 3.3 - Numéros de séquence de la RFC 793.

Pour un aperçu de l'ensemble du processus avec et sans prise en charge de la reconnaissance sélective, consultez cet article (qui comprend des diagrammes très utiles).

Percée
la source
c'est un peu étrange pour moi, car TCP est un protocole basé sur les flux et orienté sur les octets. Pourquoi devrait-il retransmettre tout le segment? Il me semble que TCP sans SAKC est un protocole de flux orienté segment, mais TCP avec Sack est vraiment orienté octet. Je pense que le RFC ne développe pas spécifiquement à ce sujet.
misteryes
comment la pile TCP gère son tampon d'envoi, est-ce la même chose que ce que j'ai écrit dans la question mise à jour.
misteryes
@misteryes cet article décrit le processus (avec de superbes diagrammes aussi!).
Percée
Dans le lien que vous avez recommandé, il semble que l'auteur discute toujours du problème d'une manière orientée segment, et non de manière orientée octets réels. N'est-ce pas?
misteryes
1
Je connaissais SACK avant de poster cette question. Au tout début, je ne pense pas que SACK ait quelque chose à voir avec cette question. À mon avis, si TCP n'est pas orienté octet mais orienté segment, alors SACK devrait également être le même. La différence entre SACK activé et SACK désactivé est qu'avec SACK, TCP autorise un trou de séquence dans ack_seq. Mais je pensais que le trou de séquence correspond à un segment. alors que selon votre dicton, le trou peut être la moitié / partie d'un segment.
misteryes
3

La taille des segments peut (et change) au cours de la durée de vie d'une connexion. Heureusement, TCP n'a pas besoin d'enregistrer la taille de segment avec laquelle les paquets individuels ont été envoyés précédemment. Par conséquent, il fera ce qui suit:

  1. Chaque fois qu'un ACK arrive, avancez le pointeur sur le premier octet non acquitté en conséquence et jetez tout tampon désormais inutile.
  2. Lorsque le besoin se fait sentir pour une retransmission (retransmission rapide ou délai d'expiration; PAS immédiatement après la réception du premier ACK!), Il sera renvoyé dans la taille de segment actuellement valide à partir du pointeur vers le premier octet non acquitté.

Les deux opérations sont effectuées indépendamment de la taille du segment dans lequel ces octets ont été envoyés à l'origine. La théorie devrait donc correspondre à la plupart des implémentations.

Permettez-moi de donner quelques informations pour expliquer:

TCP utilise-t-il des octets ou des segments? Pour l'application, TCP expose une interface de flux d'octets. De plus, tous les champs d'en-tête et les variables internes sont en octets. Cependant, pour transmettre des informations, TCP les segmente en segments, car envoyer des octets un par un serait un gaspillage :-). L'utilisation de compteurs d'octets partout a l'avantage que la taille du segment n'a pas besoin de rester constante pendant la durée de vie de la connexion:

  • Des options sont introduites, par exemple le ferroutage d'un SACK sur une retransmission (les implémentations réelles le rencontreront rarement, voire pas du tout)
  • Le chemin MTU change, par exemple un lien le long du chemin passe à un MTU inférieur ou le lien MTU goulot d'étranglement est levé. Cela se produit lorsque des tunnels sont établis (VPN, PPPoE) ou que le protocole de routage sélectionne une liaison MTU différente. Cela se produit dans IPv4 avec le jeu Don't Fragment (vrai pour la plupart des TCP modernes); toujours en TCPv6).

BTW: SACK n'est pas la réponse ici, car le récepteur n'utilisera (généralement) SACK que s'il reconnaît un trou dans le flux d'octets (c'est-à-dire si un paquet s'est perdu mais qu'un paquet suivant est arrivé).

Marcel Waldvogel
la source