9
votes

Que puis-je faire pour éviter la fenêtre TCP Zero Window / TCP Full sur le côté récepteur?

J'ai une petite application qui envoie des fichiers sur le réseau à un agent situé sur un système d'exploitation Windows.

Lorsque cette application s'exécute sous Windows, tout fonctionne bien, la communication est correcte et les fichiers sont tous copiés avec succès. < / P>

Mais, lorsque cette application s'exécute sur Linux (RedHAT 5.3, le récepteur est toujours Windows) - Je vois dans les messages de trace réseau Wireshark Network de la fenêtre Zéro TCP et la fenêtre TCP pleine pour apparaître sur chaque 1-2 secondes. L'agent ferme ensuite la connexion après quelques minutes.

Le code Windows - Linux est presque identique et assez simple. La seule opération non triviale est Setockopt avec SO_SNDBUF et la valeur de 0xFFFF. Supprimer ce code n'a pas aidé.

Quelqu'un peut-il m'aider s'il vous plaît avec ce problème?

EDIT: Ajout du code d'envoi - il semble qu'il gère Écris correctement partiels: xxx

merci d'avance.


5 commentaires

Plus de détails? Le fichier est-il transféré avec succès, seulement à un taux plus lent ou est l'échec du transfert? Si c'est échoué, où est-ce échouant? Est-ce que quelque chose qui passe ou est-ce que cela échoue à mi-chemin?


@Robert, merci. Le transfert échoue. Si je transfère un dossier contient, par exemple, 2 Go de 3 Go de 3 KB - 50 Ko, il transfère parfois environ 0,5 Go, parfois ~ 1,3 Go de données puis échoue.


Quels messages d'erreur obtenez-vous et quel côté arrête-t-il la connexion? Utilisez-vous le blocage ou les E / S non bloquantes. Avez-vous un fil dédié à faire des E / S? Plus le meilleur est le meilleur, et si vous pouviez poster des fragments de code qui seraient les meilleurs.


Qu'est-ce que :: Envoyer (...) ? Est-ce un membre de votre classe qui enveloppe la fonction standard (...) ?


Pouvez-vous aussi poster le code de réception? On sonne comme des données peut ne pas être retiré à la fin de la réception.


4 Réponses :


0
votes

Le problème le plus probable est que vous avez un bogue dans votre code où vous ne gérez pas correctement les lectures partielles ou les écritures partielles correctement. TCP entre Linux et Windows est connu pour fonctionner.


0 commentaires

1
votes

Une erreur commune lors du développement avec des sockets TCP est une hypothèse incorrecte sur le comportement de lecture () / écriture ().

Lorsque vous effectuez une opération de lecture / écriture, vous devez vérifier la valeur de retour, elles n'ont peut-être pas la lecture / écriture de la demande d'octets, vous avez généralement besoin d'une boucle pour garder la piste et assurez-vous que toutes les données ont été transférées.


0 commentaires

13
votes

Ne pas voir votre code, je devrai deviner.

La raison pour laquelle vous obtenez une fenêtre nulle dans TCP est parce qu'il n'y a pas de place dans le tampon RECV du récepteur.

Il y a plusieurs façons que cela puisse se produire. Une cause commune de ce problème est que lorsque vous envoyez une connexion réseau LAN ou une autre connexion réseau relativement rapide et qu'un ordinateur est nettement plus rapide que l'autre ordinateur. À titre d'exemple extrême, indiquez que vous avez un ordinateur de 3GHz envoi aussi vite que possible sur un gigabit Ethernet à une autre machine qui exécute un processeur de 1 GHz. Étant donné que l'expéditeur peut envoyer beaucoup plus vite que le récepteur est capable de lire, le tampon RECV du récepteur se remplira à l'origine de la pile TCP pour annoncer une fenêtre nulle à l'expéditeur.

Maintenant, cela peut poser des problèmes sur les deux Envoi et réception des côtés s'ils ne sont pas tous deux prêts à gérer cela. Du côté de l'envoi, cela peut entraîner le remplissage de la mémoire tampon d'envoi et des appels à envoyer à bloquer ou à échouer si vous utilisez des E / S non bloquant. Sur le côté de la réception, vous pouvez dépenser autant de temps sur les E / S que l'application n'a aucune chance de traiter l'une de ses données et de donner l'apparence d'être verrouillée.

edit

à partir de certaines de vos réponses et de votre code, il ressemble à votre application est uniforme et que vous essayez de faire des envois non bloquants pour une raison quelconque. Je suppose que vous définissez la prise sur le non-bloquant dans une autre partie du code.

Généralement, je dirais que ce n'est pas une bonne idée. Idéalement, si vous êtes inquiet de votre application suspendue sur un envoyer (2) Vous devez définir un délai long sur la prise en utilisant setSockopt et utilisez un fil séparé pour l'envoi réel.

voir Prise (7) :

so_rcvtimeo et so_sndtimeo Spécifiez les délais de réception ou d'envoi jusqu'à ce que de signaler une erreur. Les Le paramètre est une structure Timeval. Si un blocs de fonction d'entrée ou de sortie pour cette période de temps et les données ont été envoyé ou reçu, la valeur de retour de cette fonction sera la quantité de données transférées; Si aucune donnée n'a été transféré et le délai d'attente a été atteint alors -1 est retourné avec errno placé sur egain ou ewouldblock tout comme Si la prise était spécifiée pour être non bloque. Si le délai d'attente est réglé sur zéro (la valeur par défaut) alors l'opération ne fera jamais le délai d'expiration.

Votre thread principal peut pousser chaque descripteur de fichier dans un Queue < / code> en utilisant un boost mutex pour l'accès à la file d'attente, puis démarrez des threads 1 - N pour effectuer l'envoi réel à l'aide d'E / S Blocking avec des délais d'envoi.

Votre fonction d'envoi devrait ressembler à quelque chose comme ceci (en supposant que vous définissez un délai d'attente): xxx

the msg_nosignal drapeau garantit que votre application n'est pas tuée en écrivant à une prise été fermé ou réinitialisé par le pair. Parfois, les opérations d'E / S sont interrompues par des signaux et vérifiant eintr vous permet de redémarrer le envoyer .

Généralement, vous devez appeler Dosend dans une boucle avec des morceaux de données de TCP_MAXSEG taille.

du côté de la réception, vous pouvez écrire une fonction de recv blocage similaire à l'aide d'un délai d'attente dans un fil séparé.


1 commentaires

Merci pour ce post. Il est très informatif, notamment le msg_nosignal que je pense est mon problème sur l'une de mes applications.



0
votes

J'ai essayé de désactiver l'algorithme de Nagle (avec TCP_Nodelay) et d'une manière ou d'une autre, cela a contribué. Le taux de transfert est beaucoup plus élevé, la taille de la fenêtre TCP n'est pas pleine ou réinitialisée. La chose étrange est que lorsque j'ai chende la taille de la fenêtre, il n'avait aucun impact.

merci.


2 commentaires

C'est vraiment étrange. Nagle typiquement désactivé n'est utile que pour les applications en temps réel où vous souhaitez avoir une très faible latence au détriment de la gaspillage de la bande passante. La désactivation du transfert de fichier en vrac semble contre-intuitive. Avez-vous réellement testé et vu de manière objective que désactivant Nagle est ce qui fait la différence? Peut-être qu'un autre changement que vous avez fait pourrait être responsable?


@Robert S. Barnes: C'est vraiment étrange, je suis d'accord. Mais c'est le seul changement qui a été fait et cela a aidé. De plus, le côté récepteur a déjà désactivé Nagle. Je sais que cela peut faire référence à un problème fondamental sous-jacent qui se cache quelque part, en attendant de sauter et de mordre à un autre moment. Mais comme une solution de contournement, il est assez bon.