none
Timeout et socket asynchrone. RRS feed

  • Discussion générale

  • Bonjour,

    Lors d'échange de données entre un client et un équipement qui fait office de serveur. En cas de perte de connexion, j'ai remarqué qu'il y a un certains laps de temps bien déterminé qui s'écoule avant que le SendCallback (qui est executé par BeginSend) ne lance une exception.

    Je voudrais savoir s'il y a un moyen de contrôler ce temps pour le réduire ou l'augmenter afin que je puisse gérer un timeout lors de l'envoie de données.

    En effet, je démarre un timer avec un certain intervalle pour l'envoie de données et tant que je n'ai pas de Recieve pour stoper le timer, il y 'aura 3 trois tentatives d'envoi au bout des quels si je ne reçois toujours pas de réponse, je sais qu'il y un problème de connexion et dans ce cas je peux effectuer un traitement.

    Or, si je peux le qualifier ainsi c'est que j'ai deux timeout à devoir gérer le mien et celui du SendCallback. Alors, je ne sais pas comment faire ?

    Cordialement,


    Beel

    • Type modifié beela jeudi 10 octobre 2013 12:45 Rectification
    • Type modifié Aurel Bera lundi 21 octobre 2013 07:43 Discussion
    jeudi 10 octobre 2013 09:22

Toutes les réponses

  • Bonjour,

    Je voudrais savoir s'il y a un moyen de contrôler ce temps pour le réduire ou l'augmenter afin que je puisse gérer un timeout lors de l'envoie de données.
    Vous ne pouvez pas gérer un timeout des sockets avec les méthodes asynchrones.

    Vous devez donc gérer vous même le mécanisme de Timeout, voilà un moyen de le faire très simplement avec des tâches :

    static void Main(string[] args)
    {
        Socket socket;
        socket = .... ;
    
        Task.Factory.StartNew(() =>
        {
            Send(socket, new byte[] { ... }, 1000, OnSended);
        });
    }
    
    static void OnSended()
    {
        // Donné reçue avant 1 seconde
    }
    
    static void Send(Socket socket, byte[] data, int timeOut, Action callback)
    {
        // Appeler la méthode Send() de manière asynchrone
        // via une tâche
        Task t;
        t = Task.Factory.StartNew(() =>
        {
            socket.Send(data);
        });
    
        // Attendre la tâche de "timeOut" millisecondes
        if (t.Wait(timeOut) == false)
        {
            // Si Wait() retourne false, c'est que la méthode Send()
            // n'a toujours pas répondu, fermer le socket 
            socket.Close();
        }
        else
        {
            // L'appel Send() s'est terminée avant les "timeOut" millisecondes,
            // appeler la méthode callback
    
            callback();
        }
    }

    Indiquez nous si cela correspond à votre besoin.

    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

    jeudi 10 octobre 2013 21:01
    Modérateur
  • Bonjour,

    Je vais donc devoir abandonner l'utilisation asynchrone et me pencher vers l'utilisation synchrone de socket pour essayer votre solution.

    Merci à vous,


    Beel

    vendredi 11 octobre 2013 13:46
  • Bonjour,

    Une autre question: est-ce qu'il est possible alors de stopper ou d'annuler un SendCallback ?


    Beel

    lundi 14 octobre 2013 06:40
  • Bonjour,

    Il faut dans ce cas récupérer votre socket et le fermer (en appelant la méthode Close()).

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance - P.O.S Informatique
    Blog : http://gilles.tourreau.fr - Suivez-moi sur Twitter
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCSA : SQL Server 2012
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0 / TFS 2010 / Windows Azure

    lundi 14 octobre 2013 18:23
    Modérateur
  • Bonjour,

    Merci pour votre proposition. Mais, le Close ne répond à mon problème. Pour être plus précis, voici la situation:

    En fait, j'ai une routine qui fait des Send toutes les secondes(sachant que je suis dans un état de socket.Connected), mais dès qu'une déconnexion se produit, je ne suis avertis de cette déconnexion que quelques secondes après par une exception générée par un RecieveCallback.

    Entre temps plusieurs threads ont été crées puisque chaque Send déclenche un (socketListener.BeginSend(byteData, 0, byteData.Length, 0,new AsyncCallback(SendCallback), socketListener)).

    C'est pourquoi, je pensais qu'il existait un moyen d'annuler ces SendCallback pour ne pas se retrouver avec une multitude de threads qui restent en suspens.

    Finalement, la question est de savoir maintenant, s'il y a un moyen de vérifier l'état de connexion avant d'envoyer un éventuel Send ou de savoir comment être averti par cette déconnexion avant d'envoyer le Send suivant.

    Cordialement,


    Beel


    • Modifié beela mercredi 16 octobre 2013 14:00 Précision
    mercredi 16 octobre 2013 13:52
  • Bonjour,

    Il n'est pas possible d'annuler l'ordre d'envoi ou de réception dans les Socket.

    Entre temps plusieurs threads ont été crées puisque chaque Send déclenche un (socketListener.BeginSend(byteData, 0, byteData.Length, 0,new AsyncCallback(SendCallback), socketListener)).
    Malheureusement, c'est à vous de gérer ce cas si vous utilisez des méthodes asynchrones... (Via un booléen qui indique que vous avez perdu la connexion. Il faudra aussi gérer le fait que le premier thread traite l'erreur et pas les autres grâce à ce booléen).

    Avez-vous essayé ma solution avec des tâches ? Il suffit juste de mettre un Wait() de 900 millisecondes...

    Finalement, la question est de savoir maintenant, s'il y a un moyen de vérifier l'état de connexion avant d'envoyer un éventuel Send ou de savoir comment être averti par cette déconnexion avant d'envoyer le Send suivant.
    Je ne suis pas sûre mais je crois que vous pouvez vous baser sur le booléen Connected du Socket. Il n'y a pas d'autre moyen de vérifier l'état de la connexion d'un Socket à part envoyer ou recevoir des données.

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance - P.O.S Informatique
    Blog : http://gilles.tourreau.fr - Suivez-moi sur Twitter
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCSA : SQL Server 2012
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0 / TFS 2010 / Windows Azure

    mercredi 16 octobre 2013 21:21
    Modérateur
  • Bonjour,

    J'ai essayé votre solution avec la création de tâche, mais ça ne résout pas mon problème.

    public void Send(byte[] byteData)
    {
         if (statutConnexion == true) // Connecté
         {
              Task.Factory.StartNew(() =>
              {
                   SendDatas(socListener, byteData, 1000, OnSended);
              });

         }
         else if (!IsConnecting)
         {
              TryToConnect();
         }
    }

    private void SendDatas(Socket socket, byte[] byteData, int timeOut, Action callback)
    {
         try
         {
              Task taskSend;
              taskSend = Task.Factory.StartNew(() =>
              {
                   socListener.Send(byteData);
              });

              if (taskSend.Wait(timeOut) == false)
              {
                   statutConnexion = false;
                   socListener.Close();
              }
              else
              {
                   callback();
              }
         }
         catch (Exception ex)
         {
              //
         }
    }

    private void OnSended()
    {
       //Send Ok
    }

    Même avec une perte de connexion avec le serveur, lors du Send le (t.Wait(timeout) n'est jamais à "false").

    Donc, apparemment,  il n' y a pas moyen de détecter une perte de connexion pendant l'execution d'un Send, si ce n'est d'être averti par un receiveCallBack qu'après que quelques secondes soient écoulées(20 à 25 secondes).

    Or, moi je voudrai savoir que quand, il y a une connexion qui est établie et que j'envoie toutes les secondes un Send, l'un après l'autre et que dès qu'il y a une deconnexion, être averti  avant d'envoyer le Send suivant sans attendre le receiveCallback. D'une autre manière, trouver un moyen de vérifier s'il y une connexion ou pas avant d'envoyer un Send.

    Cordialement,

    • Modifié beela jeudi 17 octobre 2013 11:06 correction
    jeudi 17 octobre 2013 06:40
  • Bonjour,

    Est-ce que vous utilisez le .NET Framework 4.0 ?

    Je peux simplifier mon code afin de n'a pas utiliser les lambda expressions, mais il y a aura plus de ligne de code.

    Vous utilisez BeginSend() et donc l'asynchronisme des socket qui ne permet pas de gérer des Timeout qui répondrait à votre problème. La solution est d'utiliser la méthode Send() de manière synchrone, et en parallèle attendre 1000 millisecondes. Si on n'a pas de réponse au bout de 1000 millisecondes on ferme la socket.  

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance - P.O.S Informatique
    Blog : http://gilles.tourreau.fr - Suivez-moi sur Twitter
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCSA : SQL Server 2012
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0 / TFS 2010 / Windows Azure

    jeudi 17 octobre 2013 10:46
    Modérateur
  • Bonjour,

    Pourquoi ne pas utiliser la propriété SendTimeout et ReceiveTimeout qui dans Socket ?

    Exemple : socket.SendTimeout = 1000; (timeout à 1 seconde)


    Merci de valider par "Proposer comme réponse" si celle-ci répond à votre demande !

    jeudi 24 octobre 2013 14:42
  • Bonjour,

    Parceque les méthodes asynchrone de la classe Socket n'en tiennent pas compte.

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance - P.O.S Informatique
    Blog : http://gilles.tourreau.fr - Suivez-moi sur Twitter
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCSA : SQL Server 2012
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0 / TFS 2010 / Windows Azure

    vendredi 25 octobre 2013 07:15
    Modérateur