J'ai un serveur simple qui reçoit une chaîne du client et l'imprime à l'écran.
J'ai aussi un client simple, envoi de données et fermeture: et avec une chaîne non motivée 'thread.sleep (100) "ça marche ok.
Mais lorsque le client commentant, parfois (1 sur 5-10 exécutions), le client n'envoie pas la chaîne.
Regarder WireShark et netstat J'ai remarqué que le client envoie Syn, ACK Package, établit la connexion et les sorties sans rien envoyer et sans fermer la prise. P> Est-ce que quelqu'un pourrait expliquer ce chef? Pourquoi dormir aide? Qu'est-ce que je fais mal? P> upd upd: p> avec cet exemple de code Ajout de flush () Avant la fermeture fonctionne vraiment, merci Fox32. P> mais après son retour à mon code initial: p> et cela ne fonctionne pas, même avec NODELAY. C'est mauvais - à l'aide de StreamWriter sur le flux de réseau? P> upd: p> Voici le code du serveur: p> dans la classe serveur: < / p> upd upd: p> Ajout même dormir (1) Déplacez des accidents dans 1 des 30 à 50 clients courants en même temps.
Et ajouter le sommeil (10) semble résoudre totalement cela, je ne peux attraper aucun crash.
Ne comprenez pas, pourquoi la prise a besoin de ces multiples millisecondes pour fermer correctement. P> p>
5 Réponses :
Dans presque tous les cas, vous êtes censé appeler Votre code contient essentiellement une condition de course avec la pile TCP. P> paramètre Je veux souligner que malheureusement Selon le réflecteur, si vous avez déjà accédé à shutdown code> sur un socket code> ou
tcpclient code> avant de le disposer. Les disposer de la connexion brutalement tuent la connexion.
NODELay code> est également une solution pour cela, mais fait mal à la performance. Calling
Flush code> IMHO résulte toujours d'une fermeture désordonnée. Ne le faites pas parce qu'ils sont juste des hacks qui peignent sur le problème en cachant les symptômes. Appeler
shutdown code>. P>
shutdown code> être appelé sur la prise
est le code> est le seulement Strong> Solution valide que je connaisse. Même
flush code> force les données sur le réseau. Il peut encore être perdu en raison d'un réseau Hickup. Il ne sera pas retransmis après
fermer code> a été appelé parce que
fermeture code> est un tuer grossier sur la prise. P>
getStream code> ce problème se pose et fermer ne ferme pas la prise sous-jacente. Dans mon estimation, ce bogue a été produit car le développeur ne connaissait pas vraiment l'importance de l'arrêt
code>. Peu de gens savent et de nombreuses applications sont buggy à cause de cela. une question connexe. P> p>
Il n'y a pas d'arrêt code> sur un tcpclient, il n'y a que ferme code>?
S'il vous plaît voir la réponse mise à jour. J'ai fait de nouvelles recherches. Cela explique parfaitement les symptômes de la question.
@USR de l'article MSDN sur le bogue Il est indiqué pour résoudre ce problème, fermez l'objet NetworkStream associé que la méthode TCPClient GetStretream retourne. Code> que l'OP est en cours, il n'ya donc pas besoin d'appeler
Arrêt () Code>
IMHO L'article est faux, c'est pourquoi j'ai donné une solution différente dans le code. Si de près est appelé ou pas importe beaucoup ici. La clé est d'appeler l'arrêt (je me fiche de la façon dont). Êtes-vous d'accord avec cela? Sinon, quels vous posez-vous spécifiquement de questions sur cette réponse?
Dans tous les cas, aucune autre solution ne fonctionnera à l'exception de la fermeture. Consultez mon commentaire sur l'autre réponse très votée qui, à mon avis, est dangereuse.
Le Vous avez plusieurs façons de résoudre ce problème: p>
Le Désactiver l'algorithme de Nagle: set La dernière option consiste à définir le < Code> lingerstate code> du tcpclient code> utilise le algorithme de Nagle et attend pour plus de données avant de l'envoyer sur le fil. Si vous fermez le socket à rapide, aucune donnée n'est trasmatisée. P>
NetworkStream code> a une méthode code> flush code> pour rincer la teneur en flux (je ne sais pas si cette méthode fait quelque chose du commentaire sur MSDN) P>
NODELAY code>
du tcpclient code> à true. P>
tcpclient code>.
Fermer code> A> Méthode Documentation STATS, que le
lingerstate code> est utilisé lors de l'appelant
Fermer code> P>
Bien que toutes ces solutions fonctionnent, je crains que tous ne garantissent pas la livraison. Même affleurant force les données sur le réseau. Il peut encore être perdu en raison d'un réseau Hickup. Il ne sera pas retransmis après étroite a été appelé car la fermeture est un tuer grossier sur la prise.
Dans votre code côté serveur, vous n'appelez que J'ai essayé de reproduire votre problème avec la quantité minimale de code et n'a pas été capable de. Le serveur imprime le message des clients à chaque fois. Aucun paramètre spécial tel que lisez () code> une fois, mais vous ne pouvez pas supposer que les données seront disponibles lorsque vous appelez Lecture. Vous devez continuer à lire dans une boucle jusqu'à ce que plus aucune donnée soit disponible. Voir l'exemple complet ci-dessous.
nodelay code> et non explicite
ferme () code> ou
flush () code>, juste
en utilisant des déclarations code> Toutes les ressources sont correctement disposées. p>
Pouvez-vous essayer de minimiser le sommeil entre les clients en cours d'exécution? J'ai attrapé plus d'accidents avec de nombreux clients courants en même temps. De plus, vous exécutez des clients un par un, j'ai exécuté plusieurs clients en même temps. Mais de toute façon, c'est étrange. Je vais essayer de reproduire ce bogue sur un autre ordinateur. Peut-être qu'il s'agit d'un bogue d'ordinateur local ..
@ Vorobey1326 J'ai mis à jour l'exemple à la queue 1000 clients sur la piscine de thread à la fois. À partir de la sortie, il semble que tous les 1000 clients arrivent sur le serveur et sont imprimés.
Votre code fonctionne bien sur mon ordinateur. Aucune exception. Merci pour cela, je vais essayer de découvrir, quelle est la différence entre votre code et la mienne et écrivez à ce sujet plus tard.
Bien sûr, faites-moi savoir si vous avez des questions sur le code.
J'ai ajouté une réponse à cette question avec du code qui reproduira probablement ce bogue. Si vous le pouvez, essayez-le sur votre ordinateur.
upding:
J'ai testé ce bogue sur plusieurs ordinateurs et rien ne s'est écrasé. On dirait que c'est un bug local sur mon ordinateur. P>
endofupd p>
Donc, ce que j'ai trouvé sur la reproduction de ce bogue. @Desperttar - Votre code fonctionne bien. Mais cela ne reproduit pas les conditions de ce bogue. Sur le client, vous devez envoyer des données et cesser de fumer après. Et dans votre code, de nombreux clients envoient des données et après la fermeture de toutes les applications. P>
Voici comment je le teste sur mon ordinateur: J'ai serveur (simplement accepter la connexion et imprimer des données entrantes), le client (il envoie simplement des données une fois les sorties de fin) et l'utilitaire exécutant (exécute le client Exe plusieurs fois). P>
Donc, je commence à exécuter utilitaire de serveur à le dossier des clients et le gère. L'utilisation de l'ulilité démarre 150 clients se connectant au serveur et 5-10 d'entre eux meurent (je vois une erreur dans la console du serveur). Et noter le thread.sleep () sur le client fonctionne bien, pas d'erreurs. P>
Peut essayer de reproduire cette version du code? P>
Code client: P>
class Program { static int port = 26140; static AutoResetEvent waitHandle = new AutoResetEvent(false); static void Main(string[] args) { StartServer(); waitHandle.WaitOne(); Console.ReadLine(); } static void StartServer() { Task.Factory.StartNew(() => { try { TcpListener listener = new TcpListener(port); listener.Start(); Console.WriteLine("Listening..."); waitHandle.Set(); while (true) { TcpClient theClient = listener.AcceptTcpClient(); Task.Factory.StartNew(paramClient => { try { TcpClient client = (TcpClient) paramClient; byte[] buffer = new byte[32768]; MemoryStream memory = new MemoryStream(); using (NetworkStream networkStream = client.GetStream()) { networkStream.ReadTimeout = 2000; do { int read = networkStream.Read(buffer, 0, buffer.Length); memory.Write(buffer, 0, read); } while (networkStream.DataAvailable); string text = Encoding.UTF8.GetString(memory.ToArray()); } } catch (Exception e) { Console.WriteLine("ERROR: " + e.Message); } }, theClient); } } catch (Exception e) { Console.WriteLine(e); } }, TaskCreationOptions.LongRunning); } }
Quelle est la exception exacte que vous obtenez?
Oh, désolé je n'ai pas écrit. Une exception est lancée dans la ligne de serveur 'NetworkStream.Lead' après 2 secondes délais. La chaîne d'exception est 'une tentative de connexion échoua car la partie connectée n'a pas répondu correctement après une période de temps, ou une connexion établie a échoué car l'hôte connecté n'a pas réussi à répondre ».
@Despertar, j'ai essayé ce code sur plusieurs ordinateurs - rien ne s'est écrasé. On dirait que c'est mon bug local. Étrange.
J'ai essayé le code, reproduisant ce bogue sur plusieurs ordinateurs. Personne ne se bloque. On dirait que c'est mon bogue d'ordinateur local. P>
Merci pour tout le monde pour avoir essayé de m'aider. p>
Quoi qu'il en soit, c'est tellement étrange. Si je découvrirai pourquoi ce bug existe sur mon ordinateur, j'écrirai à ce sujet. P>
Vous devez probablement voler le flux d'abord et / ou définir la prise TCP sur NODELAY ou ATTERGER
Vous ne pouvez pas affleurer un flux de réseau, mais la fermeture des données tamponnées / non délaises causées par Nagles Algorithm.
Remarqué que l'erreur avec l'envoi apparaît rarement lors de l'exécution de clients uniques avec un grand délai. Et apparaît presque toujours lors de la gestion de nombreux clients en même temps.
Pouvez-vous montrer une quantité minimale du code côté serveur, en particulier la façon dont vous lisez et fermez les flux?
@Despertar, j'ai ajouté du code serveur pour publier.
J'ai essayé beaucoup de méthodes: déconnecter, fermer, affleurer, arrêt. Tout se bloque parfois. Et le sommeil fonctionne bien. Étrange.
Pouvez-vous publier votre code actuel, avec tous i> ces méthodes appliquées? Le code posté ne fait pas l'arrêt. En outre, votre serveur est buggy. Vous supposez que votre première lecture reviendra réellement tous les octets envoyés. Ceci n'est pas garanti. Est-ce que tu comprends ce que je veux dire?
@USR, oui, bien sûr - le serveur de droite doit lire jusqu'à ce qu'il y ait des données dans le flux de réseau. C'est juste un serveur de test pour la lecture de petites chaînes) sur le code de publication - Despertar a posté la réponse avec le code de travail - aucune exception. Je vais bientôt écrire ce qui n'allait pas avec mon code, j'espère. Si je ne traite pas de cela, je posterai mon code complet sans travail avec toutes les méthodes. D'accord?
Bien sûr, je serais intéressé par ce que vous avez trouvé. (Sachez que le code affiché est incorrect car il utilise NetworkStream.DataVailable qui n'est pas fiable).