Quelle est la bonne manière de lire à partir de NetworkStream .NET

J'ai eu du mal avec cela et ne peut pas trouver une raison pourquoi mon code ne s'est pas correctement lues à partir d'un serveur TCP j'ai également écrit. Je suis à l'aide de la TcpClient classe et de son GetStream() méthode, mais quelque chose ne fonctionne pas comme prévu. Soit l'opération bloque indéfiniment (la dernière opération de lecture n'a pas de délai d'attente comme prévu), ou les données sont tronquées (pour une raison quelconque, une opération de Lecture renvoie 0 et sort de la boucle, peut-être que le serveur ne répond pas assez vite). Ces trois tentatives de mise en place de cette fonction:

//this will break from the loop without getting the entire 4804 bytes from the server 
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
bytes = 0;
if (stm.DataAvailable)
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
//this will block forever. It reads everything but freezes when data is exhausted
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
//inserting a sleep inside the loop will make everything work perfectly
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
Thread.Sleep(20);
bytes = 0;
if (stm.DataAvailable)
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}

La dernière "marche", mais il est certainement plus laid mettre codés en dur pour dormir à l'intérieur de la boucle considérant que les sockets déjà lu délais d'attente! Dois-je configurer quelque propriété(s) sur le TcpClient de la NetworkStream? Le problème réside dans le serveur? Le serveur ne ferme pas les connexions, c'est au client de le faire. Le ci-dessus est également en cours d'exécution à l'intérieur de la thread de l'INTERFACE utilisateur contexte (programme de test), peut-être qu'il a quelque chose à faire avec ça...

Ce que quelqu'un sait comment utiliser correctement NetworkStream.Read de lire les données jusqu'à ce que plus de données sont disponibles? Je suppose que ce que je souhaite, c'est quelque chose comme l'ancien Win32 winsock propriétés de délai d'expiration... ReadTimeout, etc. Il essaie de lire jusqu'à ce que le délai est atteint, et ensuite de retour à 0... Mais il semble parfois return 0 lorsque les données doivent être disponibles (ou sur le chemin.. peut Lire retourner 0 si est-il disponible?) et puis, il bloque indéfiniment sur la dernière lecture lorsque les données n'est pas disponible...

Oui, je suis à une perte de!

Être prudent. Le code dans votre tentative (et les réponses) ne pas fermer client ou d'un ruisseau, ce qui provoque une fuite de ressources avec de grandes conséquences si elle est appelée à plusieurs reprises. Vous devriez faire using (var client = new System.Net.Sockets.TcpClient(ip, port)) using (var stm = client.GetStream()) puis placez le reste de la méthode dans des accolades. Cela permettra de garantir que sur la méthode de sortie, quelle que soit la raison, les connexions sont fermées, les ressources sont récupérés.
Avez-vous vu le code de la classe TcpClient? Je conseille de prendre un coup d'oeil... Si vous avez encore envie de vous répondre sur le point de terminaison, vous ne devez pas fermer le flux de données, ni le tcpclient (qui ferme le flux, si je ne me trompe pas). Mais le code que j'utilise est différent, je vais creuser et mettre à jour les réponses ici aussi.
merci pour la suggestion. J'ai trouvé TCPClient.cs. En effet, la fermeture ou de l'élimination de TCPClient dispose le flux. En fait, j'ai vu des échecs de connexion lorsqu'un programme fait des milliers de connexions sans beaucoup de soin (pour les autres, les mauvais, les raisons). Pourquoi devrait-on s'écarter de l'habituel IDisposable modèle ici ? La mise en œuvre de IDisposable est sujette à erreur, using() c'est facile et sûr.

OriginalL'auteur Loudenvier | 2012-10-27