none
Problème avec TCPClient/TCPListener RRS feed

  • Question

  • Bonjour,
    Je suis entrain de développer une application client/serveur dans le cadre de mes études, j'ai rencontré quelques problèmes et j'espère que vous pourriez m'aider:
    1/ J'ai fait un code qui permet au client d'envoyer un objet sérialisé au serveur, ce dernier le reçoit et va préparer une réponse. Mon problème, c'est comment modifier mon code pour que le serveur puisse recevoir et envoyer les données au même temps. En fait, j'ai créer un thread à chaque acceptation d'un client qui va écouter les messages. Est ce que je dois créer aussi pour chaque client connecté un thread pour répondre ?
    Si oui, je ne peux pas créer un seul thread par client qui gère tout (communication client/serveur).

    2/ J'ai un autre souci, le client peut envoyer plusieurs demandes différentes, le serveur toujours en écoute doit interpréter la demande et va lancer l'exécution de la réponse. Là, je n'ai pas une grande idée comment je dois faire ?

    Merci
    samedi 11 avril 2009 08:38

Toutes les réponses

  • Bonjour,

    Tu dois nous montrer ton code si tu veux que l'on t'aide.
    a+

    fred
    dimanche 12 avril 2009 22:48
  • Bonjour,
    coté serveur tu dois avoir:
    -le Main thread c'est à dire ton programme serveur
    -le Dispatcher Thread qui traite chaque demande client pour créer le thread approprié selon le type de la demande:
    si demande A:  crée le Thread A
    si demande B: crée le Thread B
    ......
    ainsi de suite
    -le Client thread créer a chaque demande client par le dispatcher pour traiter la demande client.
    jeudi 30 avril 2009 09:06
  • Moi, je pencherais du coté d'un ThreadPool.
    Paul Bacelar, MVP VC++
    jeudi 30 avril 2009 11:43
  • J'ai un problème avec l'objet NetworkStream, et-il nécessaire de le fermer apres chaque envoie ou réception de données. Voilà mon contexte :
    A partir d'un form j'initialise l'objet TCPCLient et je me connecte au serveur (tout marche bien). Quand la connexion est réussit je passe l'objet TCPCLient à une deuxième form pour effectuer d'autres envoies des données au serveur. Du coup, je fais objCLi.GetStream(). Mais, je ne peux pas envoyer ni recevoir des données via ce stream. J'étais obligé donc de ne pas fermer le stream dans la première fenetre.
    Je souhaite savoir cpmment garder la même socket et le même flux (stream) entre les différentes interfaces de mon application pour pouvoir échanger les données avec le serveur.

    Mon code a cette allure :

    try
              {
                client = new TcpClient(serveur, port);
                identClient.LoginClient = txtLogin.Text.ToString();
                identClient.PasswordClient = txtPassword.Text.ToString();
                //identClient.LoginConnexionClient = "Authentification";
                fluxClient = client.GetStream(); // the stream
    
                #region Envoyer le login et le mot de passe au serveur
                if (fluxClient.CanWrite)
                {
                    MemoryStream ms = new MemoryStream();
                    IFormatter bf = new BinaryFormatter();
                    bf.Serialize(ms,identClient);
                    byte[] writerbuffer = ms.GetBuffer();
                    fluxClient.Write(writerbuffer, 0, writerbuffer.Length);
                    ms.Close();
                } 
                #endregion
                
                #region Désérialisation et récupération de la réponse du serveur
                
                if (fluxClient.CanRead)
                {
                    byte[] data = new byte[client.ReceiveBufferSize];
                    MemoryStream ms2 = new MemoryStream(data);
                    fluxClient.Read(data, 0, (int)client.ReceiveBufferSize);
                    IFormatter formatter = new BinaryFormatter();
                    Object obj = (Object)formatter.Deserialize(ms2);
                    if (obj.GetType() == typeof(bool))
                    {
                        connecte = (bool)obj;
                        if(connecte==false)
                            MessageBox.Show("Votre login et mot de passe est incorrect !");
                    }
                    else if (obj.GetType()== typeof(DataTable))
                    {
                        dt = (DataTable)obj;
                       
                        FormMessage f1 = new FormMessage(this);
                        f1.Show();
                        this.Close();
                       
                    }
                    ms2.Close();
                }
                else
                {
                    MessageBox.Show("Impossible de lire");
                }
                #endregion
    
                fluxClient.Flush();//Ici je suis obligé de ne pas fermé ce flux car je le passe à un autre formulaire <br/>
                       //dont je vais envoyer d'autre message au serveur. Donc si je le fermer je ne peux plus envoyer des données.
              } 
              catch (Exception E) 
              {
                  MessageBox.Show(E.StackTrace);
              }
    
    Dans la partie serveur, je teste sur le type de l'objet envoyé et selon le type je lance une fonction :
    
    try
                {
    
                    server = new TcpListener(localAddrServer, portServer);
                    server.Start();
    
                    String str = "Serveur lancé, Attend des nouvelles connexions";
                    bool val = true;
    
               
                    while (deconnexion)
                    {
                        serviceClient = server.AcceptTcpClient();
                        fluxClient = serviceClient.GetStream();
                        if (serviceClient.Connected == true)
                        {
                            Clients.Add(serviceClient);
                            serviceThreadLecture = new Thread(new  ThreadStart(ListenToClient));
                            serviceThreadLecture.Start();
                       //Chaque client est un thread à part
                        }
                    }
                }
                catch (Exception E)
                {
                    MessageBox.Show(E.Message.ToString());
                }
    
    Et dans la méthode ListenToClient : je teste sur le type du traitement :
    
    public void ListenToClient()
            {
                if (fluxClient.CanRead)
                {
                    #region Désérialisation et récupération de la demande sous forme d'objet qui a plusieurs types
                    byte[] data = new byte[serviceClient.ReceiveBufferSize];
                    MemoryStream ms2 = new MemoryStream(data);
                    fluxClient.Read(data, 0, (int)serviceClient.ReceiveBufferSize);
                    IFormatter formatter = new BinaryFormatter();
                    Object objetrecu = formatter.Deserialize(ms2);
                    ms2.Close();
                    #endregion
    
                    if (objetrecu.GetType() == typeof(IdentificationClient))
                    {
                        identClient = (IdentificationClient)objetrecu;
                        this.ListenAuthentification();
                    }
                    else if (objetrecu.GetType() == typeof(EnregistrerClient))
                    {
                        nouvClient = (EnregistrerClient)objetrecu;
                        this.ListenEnregistrementClient();
                    }
                    else if (objetrecu.GetType() == typeof(GetInfoReponseMessage))
                    {
                        infoReponse = (GetInfoReponseMessage)objetrecu;
                        this.ListenGetReponse();
                    }
                }
    }
    
    Je prends l'exemple de la fonction qui m'a généré une erreur :
    
    
     public void ListenAuthentification()
            {
               
                try
                {
    
                    if (fluxClient.CanWrite)
                    {
                        if (this.getInfoUtilisateur(identClient.LoginClient, identClient.PasswordClient) != null)
                        {
                            DataTable dt = this.getMessagesNonlus(identClient.LoginClient, identClient.PasswordClient);
                            //MessageBox.Show(dt.Rows.Count.ToString());
                            MemoryStream ms = new MemoryStream();
                            IFormatter bf = new BinaryFormatter();
                            bf.Serialize(ms, dt);
                            byte[] writerbuffer = ms.GetBuffer();
                            fluxClient.Write(writerbuffer, 0, writerbuffer.Length);
                            ms.Close();
                        }
                        else
                        {
                            bool connecte = false;
                            MemoryStream ms = new MemoryStream();
                            IFormatter bf = new BinaryFormatter();
                            bf.Serialize(ms, connecte);
                            byte[] writerbuffer = ms.GetBuffer();
                            fluxClient.Write(writerbuffer, 0, writerbuffer.Length);
                            ms.Close();
                        }
                    }
                    fluxClient.Close();//Ici je dois fermer ?
    
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.StackTrace);
                }

    
    "Impossible de lire les données de la connexion de transport : une connexion établie a été abondonnée par un logiciel de votre ordinateur hôte". 

    Merci pour votre aide.
    mardi 12 mai 2009 11:24