none
Comment redémarrer ou reconnecter une socket asynchrone après avoir perdu ou arrêter manuellement la connexion avec le serveur. RRS feed

  • Question

  • Bonjour,

    J'ai une application qui doit se connecter à un équipement. Celle-ci fonctionne très bien, mon application exe démarre automatiquement, elle établi la connexion avec l'équipement et, il y a bien échange de données entre les deux.

    Seulement voilà, mon application n'implémentais pas jusqu'ici le code en cas de perte de connexion avec le serveur.

    Du coup, ne voulant pas travailler directement avec le code de mon application, je suis passé par une étape intermédiaire en créant une WindowsForm avec deux boutons: l'un pour démarrer et l'autre pour stopper la connexion manuellement.

    Quand je démarre manuellement, la connexion et le communication se font bien, cependant, dès que je fais un stop, et que j'essaye à nouveau de redémarrer la connexion, j'ai un problème, je n'arrive pas a établir à nouveau de connexion.

    Voici mon code que j'ai un peu simplifier:

    private void BTN_Start_Click(object sender, EventArgs e)
    {

         ipAddress = IPAddress.Parse("172.20.10.110");
         remoteEP = new IPEndPoint(ipAddress, port);

         socListener = null;

         socListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream,                                                                                                                 ProtocolType.Tcp);
         socListener.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), socListener);
         connectDone.WaitOne();
         Receive(socListener);

    }

    private void ConnectCallback(IAsyncResult ar)
    {
              Socket socListener = (Socket)ar.AsyncState;
              socListener.EndConnect(ar);
              connectDone.Set();
    }

    private void Receive(Socket socketListener)
    {
              StateObject state = new StateObject();
              state.workSocket = socketListener;
              socketListener.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new 
                                                                                     AsyncCallback(ReceiveCallback), state);

    }

    private void ReceiveCallback(IAsyncResult ar)
    {
         StateObject stateObj = (StateObject)ar.AsyncState;
         Socket socketListener = stateObj.workSocket;

         if (socketListener.Available != 0)
         {
              socketListener.BeginReceive(stateObj.buffer, 0, StateObject.BufferSize, 0, new
                                                                                 AsyncCallback(ReceiveCallback), stateObj);
         }
         else
         {
              int bytesRead = socketListener.EndReceive(ar);
              byte[] bytesTemp = stateObj.buffer;
              Array.Resize(ref bytesTemp, bytesRead);
              ByteData.AddRange(bytesTemp);

              if (ByteData.Count > 0)
              {
                   response = stateObj.sb.ToString();
                   if (DataReceivedClientTCP != null)
                   {
                        DataReceivedClientTCP(ByteData.ToArray());
                   }

                   ByteData.Clear();
                   receiveDone.Set();
                   socketListener.BeginReceive(stateObj.buffer, 0, StateObject.BufferSize, 0, new
                                                                               AsyncCallback(ReceiveCallback), stateObj);
              }
         }
    }

    private void BTN_Close_Click(object sender, EventArgs e)
    {
          socListener.Shutdown(SocketShutdown.Both);
          socListener.BeginDisconnect(false, new AsyncCallback(DisConnectCallback), socListener);
          DisconnectDone.WaitOne();
    }

    private void DisConnectCallback(IAsyncResult ar)
    {
              Socket socListener = (Socket)ar.AsyncState;
              socListener.EndDisconnect(ar);
              DisconnectDone.Set();
              socListener.Close();
              socListener.Dispose();
              socListener = null;
    }

    Merci d'avance pour votre réponse!


    • Modifié beela lundi 30 septembre 2013 10:32
    lundi 30 septembre 2013 10:21

Réponses

  • Bonjour,

    Sur base de votre suggestion d'utiliser AutoResetEvent à la place de ManuelResetEvent pour connectDone, est-ce que je peux faire de même pour ce qui est du Send, Receive ?
    Oui.

    Rappelez vous que le AutoResetEvent, une fois débloqué via la méthode Set(), le signal est automatiquement remise à zéro. C'est à dire que le prochain appel à la méthode WaitOne() sera bloquant...

    Le ManualResetEvent devra être reseté à la main une fois débloqué via la méthode Set(), sinon les appels à WaitOne() ne seront plus bloquants...

    2) Si je veux réutiliser la même socket pour ne pas devoir en créer à chaque fois une pour chaque reconnexion, comment dois-je procéder ? Je ne sais si le fait d'ajouter "socListener.Disconnect(true) au bouton Close est suffisant ?
    Oui, comme l'indique la documentation MSDN de la méthode Disconnect() (http://msdn.microsoft.com/fr-fr/library/system.net.sockets.socket.disconnect.aspx) "<sentencetext xmlns="http://www.w3.org/1999/xhtml">Ferme la connexion de socket et autorise la réutilisation du socket.</sentencetext>"

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    • Marqué comme réponse Aurel Bera lundi 7 octobre 2013 06:57
    mardi 1 octobre 2013 21:10
    Modérateur

Toutes les réponses

  • Bonjour,

    Quel message d'erreur obtenez vous exactement ?

    Quand vous dites "cependant, dès que je fais un stop, et que j'essaye à nouveau de redémarrer la connexion, j'ai un problème, je n'arrive pas a établir à nouveau de connexion.", vous voulez dire que vous cliquez sur le bouton BTN_Close_Click() et ensuite le BTN_Start_Click() ?

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    lundi 30 septembre 2013 22:36
    Modérateur
  • Bonjour,

    Tout d'abord merci à vous pour avoir répondu à ma question.

    Désolé, je n'ai pas été aussi explicite. Tout à fait, je clique sur le bouton BTN_Close_Click() et ensuite sur le bouton BTN_Start_Click().

    Le message d'erreur est le suivant "Une requête d'envoi ou de réception de données n'a pas été autorisée car la socket n'est pas connectée".

    J'ai essayé aussi (socListener.Disconnect(true))  pour fermer la connexion afin de pouvoir réutiliser la socket mais je n'y arrive pas non plus.

    Bien à vous,

    mardi 1 octobre 2013 08:30
  • Bonjour,

    Le problème doit certainement vernir du fait de votre événement  "connectDone". Est-il de type ManuelResetEvent ? Si oui, comme son nom l'indique vous devez appeler la méthode Reset() avant l'appel à WaitOne() afin de remettre à zéro votre signal.

    En effet, dans votre cas, lors du second appel à connectDone.WaitOne(), celui-ci libèrera directement votre code étant donné que votre événement a déjà été signalé... L'autre solution consiste à utiliser un AutoResetEvent qui se réinitialise à chaque fois que vous appelez la méthode Set().

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    mardi 1 octobre 2013 08:57
    Modérateur
  • Bonjour,

    Je vous remercie beaucoup pour vos réponses. J'ai utilisé la deuxième option avec AutoResetEvent et cela fonctionne très bien.

    En fait, je me suis inspiré d'un exemple proposé par MSDN, mais je vous avoue que je n'ai pas encore très bien compris tous les mécanisme de  connectDone, sendDone, receiveDone, DisconnectDone avec les waitOne().

    Connaissez-vous un bon tutoriel à ce sujet ?

    Si vous le permettez, puis-je vous demander encore deux questions:

    1) Sur base de votre suggestion d'utiliser AutoResetEvent à la place de ManuelResetEvent pour connectDone, est-ce que je peux faire de même pour ce qui est du Send, Receive ?

    2) Si je veux réutiliser la même socket pour ne pas devoir en créer à chaque fois une pour chaque reconnexion, comment dois-je procéder ? Je ne sais si le fait d'ajouter "socListener.Disconnect(true) au bouton Close est suffisant ?

    private void BTN_Close_Click(object sender, EventArgs e)
    {
          socListener.Shutdown(SocketShutdown.Both);
          socListener.Disconnect(true);
          socListener.BeginDisconnect(false, new AsyncCallback(DisConnectCallback), socListener);
          DisconnectDone.WaitOne();
    }

    Cordialement,

    mardi 1 octobre 2013 10:27
  • Bonjour,

    Sur base de votre suggestion d'utiliser AutoResetEvent à la place de ManuelResetEvent pour connectDone, est-ce que je peux faire de même pour ce qui est du Send, Receive ?
    Oui.

    Rappelez vous que le AutoResetEvent, une fois débloqué via la méthode Set(), le signal est automatiquement remise à zéro. C'est à dire que le prochain appel à la méthode WaitOne() sera bloquant...

    Le ManualResetEvent devra être reseté à la main une fois débloqué via la méthode Set(), sinon les appels à WaitOne() ne seront plus bloquants...

    2) Si je veux réutiliser la même socket pour ne pas devoir en créer à chaque fois une pour chaque reconnexion, comment dois-je procéder ? Je ne sais si le fait d'ajouter "socListener.Disconnect(true) au bouton Close est suffisant ?
    Oui, comme l'indique la documentation MSDN de la méthode Disconnect() (http://msdn.microsoft.com/fr-fr/library/system.net.sockets.socket.disconnect.aspx) "<sentencetext xmlns="http://www.w3.org/1999/xhtml">Ferme la connexion de socket et autorise la réutilisation du socket.</sentencetext>"

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    • Marqué comme réponse Aurel Bera lundi 7 octobre 2013 06:57
    mardi 1 octobre 2013 21:10
    Modérateur
  • Bonjour,

    Merci une nouvelle fois pour vos précieuses réponse.

    Cordialement,

    mercredi 2 octobre 2013 08:09
  • Bonjour beela

    Est que le problème est résolu?

    N’oubliez de marquer la réponse si le problème est résolu. 

    Cordialement,


    Aurel BERA, MSFT
    MSDN Community Support. LE CONTENU EST FOURNI "TEL QUEL" SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE.
    S'il vous plaît n'oubliez pas de "Marquer comme réponse" les réponses qui ont résolu votre problème. C'est une voie commune pour reconnaître ceux qui vous ont aidé, et rend plus facile pour les autres visiteurs de trouver plus tard la résolution.

    mercredi 2 octobre 2013 11:12