IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Framework .NET Discussion :

[Réseau] Utilisation de TcpClient


Sujet :

Framework .NET

  1. #1
    Membre émérite Avatar de neptune
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2003
    Messages : 835
    Par défaut [Réseau] Utilisation de TcpClient
    Bonjour à tous,

    Je me bat depuis plusieurs jours pour essayer d'écrire un client simple pour faire du Telnet.

    Mon problème majeur est la gestion des réponses provenant du serveur. Je n'arrive pas à trouver la bonne solution pour savoir déterminer que le serveur n'envoie plus rien.

    Ma meilleure solution trouvée est de mettre un timeout sur la lecture et d'attraper l'exception; mais elle ne me satisfait pas pleinement car la connexion est alors perdue.

    J'utilise les méthodes synchrones, car je ne souhaites pas que le client puisse envoyer d'autres commandes tant que la première n'est pas complètement terminée.

    Le problème majeure, est que l'information fournie par MSDN est fausse.

    This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes.
    La méthode Read (sur NetworkStream) est bloquante, tant qu'il n'y a pas de données à lire.

    Dernier point, ni TcpClient.Available, ni NetworkStream.DataAvailable ou encore Socket.Available (tous les trois les mêmes appels en fait) n'est fiable car utilisée en boucle, l'appel est beaucoup trop rapide par rapport à l'arrivée des données. Ajouter un Thread.Sleep() ne me semble pas etre une belle solution.

    Voila, désolé pour la tartine...
    Merci d'avance,

  2. #2
    Membre Expert Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Par défaut
    L'avantage du blocage au moment du Read, c'est que tu n'as plus besoin d'utiliser DataAvailable (ou autre): ton thread se bloque tout seul quand y'a rien à lire (et ton système peut se reposer).

    Si tu veux vraiment utiliser DataAvailable (ou autre), dans ce cas le Sleep est tout indiqué, car tu veux bien effectuer une temporisation entre deux vérifications.

    Maintenant, il me semble qu'on peut configurer la lecture d'un Socket pour qu'il ne soit pas bloquant. Je t'invite à chercher attentivement.

  3. #3
    Membre Expert Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Par défaut
    Citation Envoyé par msdn
    This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes.
    En fait c'est correct.

    La méthode Read est bloquante, mais elle renvoie effectivement zéro quand il n'y a plus rien à lire, exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
     
    namespace client
    {
    	class Program
    	{
    		static void Main(string [] args) {
    			TcpClient client = new TcpClient();
    			client.Connect("localhost", 6958);
    			NetworkStream stream = client.GetStream();
     
    			byte [] buffer = new byte [8];
    			StringBuilder sb = new StringBuilder();
    			while (stream.Read(buffer, 0, buffer.Length) != 0) {
    				sb.Append(Encoding.ASCII.GetString(buffer));
    			}
     
    			stream.Close();
    			client.Close();
     
    			Console.WriteLine(sb.ToString());
    			Console.ReadKey();
    		}
    	}
    }
    Evidemment, le buffer de 8 octets est juste là pour mettre le fonctionnement en évidence.

  4. #4
    Membre confirmé Avatar de despeludo
    Inscrit en
    Janvier 2004
    Messages
    121
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 121
    Par défaut
    En fait personellement pour optimiser un peu les choses par rapport à ton code j'aurais eu tendance à faire, et c'est ce que je fais en général :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        byte [] buffer = new byte [8];
        StringBuilder sb = new StringBuilder();
        while (stream.Read(buffer, 0, buffer.Length) != buffer.Length) {
             sb.Append(Encoding.ASCII.GetString(buffer));
        }
    car la méthode renvoie le nombre d'octets effectivement lus, et quand il n'y a plus rien a lire elle renvoie ce qu'elle a pu lire. Du coup tu évites un tour de boucle supplémentaire et donc un blocage

  5. #5
    Membre Expert Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Par défaut
    Citation Envoyé par despeludo
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        byte [] buffer = new byte [8];
        StringBuilder sb = new StringBuilder();
        while (stream.Read(buffer, 0, buffer.Length) != buffer.Length) {
             sb.Append(Encoding.ASCII.GetString(buffer));
        }
    car la méthode renvoie le nombre d'octets effectivement lus, et quand il n'y a plus rien a lire elle renvoie ce qu'elle a pu lire. Du coup tu évites un tour de boucle supplémentaire et donc un blocage
    Tu voulais sûrement dire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (stream.Read(buffer, 0, buffer.Length) == buffer.Length) {
    Parce qu'autrement, tu récupères pas toutes tes données.

  6. #6
    Membre confirmé Avatar de despeludo
    Inscrit en
    Janvier 2004
    Messages
    121
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 121
    Par défaut
    oui oups désolé il était tard.

  7. #7
    Membre émérite Avatar de neptune
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2003
    Messages : 835
    Par défaut
    Merci pour vos réponses, je viens de le voir, n'ayant pas reçu d'email comme quoi il y en avait!

    En attendant, j'ai finalement résolu mon problème. Je me base sur le protocole que j'implémente pour voir si je n'ai plus rien à lire. En effet, on ne pourra jamais savoir s'il y a encore à lire ou pas.

    En fait c'est correct.

    La méthode Read est bloquante, mais elle renvoie effectivement zéro quand il n'y a plus rien à lire, exemple
    Non non, la méthode reste sur Read tant qu'il n'y a rien à lire, par contre si tu met un ReadTimeout tu auras une IO exception si tu n'as rien lu après ce timeout.

    while (stream.Read(buffer, 0, buffer.Length) == buffer.Length)
    Faux également, imagine que la taille de ton buffer est égale à (ou un multiple de) la réponse totale attendue? Tu feras un read supplémentaire qui restera bloqué car tu ne reçois plus rien.

    Voici la partie de code concernée, qui fonctionne très bien actuellement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    private NntpResponse GetResponse()
            {
                NetworkStream stream = m_tcpClient.GetStream();
                int bufferSize = 1024;
                byte[] buffer = new byte[bufferSize];
                StringBuilder sb = new StringBuilder();
     
                // Read first packet
                int bytesRead = stream.Read(buffer, 0, bufferSize);
                string data = NntpDefaults.Encoding.GetString(buffer, 0, bytesRead);
                sb.Append(data);
     
                // Check if it's a status response
                if (!NntpResponse.IsStatusResponse(data))
                {
                    // It's a text reponse, read until end of text
                    while (!data.EndsWith(NntpDefaults.EndOfMessage))
                    {
                        bytesRead = stream.Read(buffer, 0, bufferSize);
                        data = NntpDefaults.Encoding.GetString(buffer, 0, bytesRead);
                        sb.Append(data);
                    }
                }
     
                return new NntpResponse(sb.ToString());
            }

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    21
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 21
    Par défaut
    Dans quel namespace trouve t-on la classe NntpResponse ?

    Merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 02/06/2010, 10h44
  2. Socket, définir l'interface réseau à utiliser
    Par psylox dans le forum Programmation et administration système
    Réponses: 4
    Dernier message: 08/12/2009, 11h12
  3. Réponses: 3
    Dernier message: 14/09/2009, 13h50
  4. Quelle bibliothèque réseau utiliser?
    Par Floréal dans le forum Bibliothèques
    Réponses: 8
    Dernier message: 19/07/2007, 19h28
  5. réseau : utiliser les ressource d'un autre pc
    Par Cornejito dans le forum MFC
    Réponses: 7
    Dernier message: 04/08/2005, 10h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo