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. P>
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é. P>
Quelqu'un peut-il m'aider s'il vous plaît avec ce problème? P>
merci d'avance. p> p>
4 Réponses :
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. P>
Une erreur commune lors du développement avec des sockets TCP est une hypothèse incorrecte sur le comportement de lecture () / écriture (). p>
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. P >
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. p>
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. P>
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. P>
edit forte > p> à 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. P> 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 voir Prise (7) : p> 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. P>
blockQuote> Votre thread principal peut pousser chaque descripteur de fichier dans un Votre fonction d'envoi devrait ressembler à quelque chose comme ceci (en supposant que vous définissez un délai d'attente): p> the Généralement, vous devez appeler 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é. P> P> envoyer (2) code >
Vous devez définir un délai long sur la prise en utilisant setSockopt code>
et utilisez un fil séparé pour l'envoi réel. P>
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. P> msg_nosignal code> 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 code> vous permet de redémarrer le
envoyer code>. P>
Dosend code> dans une boucle avec des morceaux de données de
TCP_MAXSEG CODE>
taille. p>
Merci pour ce post. Il est très informatif, notamment le msg_nosignal code> que je pense est mon problème sur l'une de mes applications.
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. P>
merci. p>
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.
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 (...) code>? Est-ce un membre de votre classe qui enveloppe la fonction standard
(...) code>?
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.