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

C# Discussion :

Utilisation asynchrone des sockets


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2008
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 92
    Par défaut Utilisation asynchrone des sockets
    Bonjour,

    J'éssaye faire de la programmation réseau asynchrone, à partir des méthodes synchrones de la classe Socket. Mais lors de mes tests, il s'est avéré que je ne pouvais pas fermer une socket, alors que celle si était en train d'attendre un message sur un autre thread. Voici le code de mon projet test :

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    public partial class Form1 : Form
    {
    Socket srv;
    Socket cli;
     
    public Form1()
    {
        InitializeComponent();
     
        string ip = "127.0.0.1";
        int port = 24000;
     
          
        // Initialisation de la socket serveur
        srv = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        srv.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
        srv.Listen(1);
     
        ThreadPool.QueueUserWorkItem(o =>
        {
            while(true)
                srv.Accept();
        });
     
          
        // Initialisation de la socket cliente
        cli = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        cli.Connect(ip, port);
     
        ThreadPool.QueueUserWorkItem(o =>
        {
            byte[] tmp = new byte[100];
            while (true)
                cli.Receive(tmp);
        });
    }
     
    // Evenement OnClick du bouton dclenchant la fermeture de la socket cliente
    private void button1_Click(object sender, EventArgs e)
    {
        cli.Shutdown(SocketShutdown.Both);
        cli.Close();
    }
    }
    D'après la documentation, la fonction Shutdown de la classe Socket devrait désactiver les envois et réceptions de données, mais cela ne fonctionne pas ( pas avec les fonctions synchrones en tout cas ).

    Vous allez me dire, ben utilises les fonctions asynchrones dans ce cas. Mais je cherche un maximum d'optimisation, et les fonctions asynchrones du framework ont d'assez mauvaises performances, selon quelques tests que j'ai put effectué.


    Donc ma question est la suivante : Comment interompre un appel bloquant, d'une fonction de socket, sans déclenché d'exeption ?

  2. #2
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2008
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 92
    Par défaut
    Si j'appelle le Shutdown juste avant le Close, l'exeption levé me dit : "Une opération de blocage a été interrompue par un appel à WSACancelBlockingCall"

    Et si je Close sans appeller le Shutdown avant, l'exeption me dit : "Une connexion établie a été abandonnée par un logiciel de votre ordinateur hôte"


    Dans le deuxième cas, je comprends parfaitement, mais dans le premier cas... c'est justement ce que je cherche à faire d'interrompre l'opération de blocage.


    Ca doit pourtant forcément être possible de pouvoir stopper un appel bloquant, de Receive par exemple ? Comment ferait on, autrement pour fermer proprement une socket ( c'est d'ailleurs ce que je cherche à faire ) ?

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Idrakis Voir le message
    J'éssaye faire de la programmation réseau asynchrone, à partir des méthodes synchrones de la classe Socket.
    Ca commence mal
    Pourquoi tu fais ça ? Socket a des méthodes asynchrones qui servent à ça... pas la peine de réinventer la roue !

  4. #4
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2008
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 92
    Par défaut
    Je l'ai précisé un peu plus loin. C'est pour des raisons de performances. Je souhaite optimiser en fonction de l'utilisation dont j'ai besoin. La différence de performances obtenue est vraiment significative, je ne galère pas pour 3 ticks qui se battent en duels, soyons clair

    De plus, l'application concerné est critique, puisqu'il s'agit d'un logiciel serveur, qui va donc avoir a utiliser sans arrets ces fonctions d'envois et de réceptions asynchrones.

    Donc voila, ça marche bien, mais je ne peut pas arreter la socket sans déclencher une exception. Or sur le serveur, les déconnexions de clients seront très fréquentes, et la gestion d'éxception perturbre grandement l'execution d'un programme.

    PS : Le bout de code présenté ci-dessus n'est qu'un code de test, pour tester si la parrallelisation des méthodes synchrone d'une socket fonctionnent bien.

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Idrakis Voir le message
    Je l'ai précisé un peu plus loin.
    Ca m'apprendra à pas lire les posts en entier

    Si tu sais quelle exception est levée, tu peux peut-être la catcher, non ? c'est pas idéal mais bon, si ça marche...

  6. #6
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2008
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 92
    Par défaut
    Le problème avec les exceptions, c'est que c'est extremement couteux en performances. Et je vais avoir besoin de fermer une socket a chaque fois qu'un client se déconnecte, donc assez régulièrement.
    Or l'interet est justement de pouvoir gagner le plus de performances possibles.

    Pour donner une idée de l'économie de performance, voici comment je gère "l'asynchronité" :

    Envois :
    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
    29
    30
    31
    32
    33
    34
    35
    private Socket Socket;
    private bool runing;
    
    private Queue<byte[]> SendBox = new Queue<byte[]>();
    private EventWaitHandle WaitForMessageToSend = new EventWaitHandle(false, EventResetMode.ManualReset);
     
    // Executé sur un thread séparé
    private void Sending() 
    {
      SocketError error;
      byte[] message;
      while (runing)
      {
         if (SendBox.Count == 0)
         {
            WaitForMessageToSend.Reset();
            WaitForMessageToSend.WaitOne();
            if (!runing)
               break;
         }
     
         lock(SendBox)
            message = SendBox.Dequeue();
     
         Socket.Send(message, 0, message.Length, SocketFlags.None, out error); 
      }
    }
    public void Send(byte[] message)
    {
       lock (SendBox)
          SendBox.Enqueue(message);
     
       WaitForMessageToSend.Set();
    }
    Réception :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public const int MaxSizeReceive = 1028;
    private byte[] tmpReceive = new byte[MaxSizeReceive];
     
    // Executé sur un thread séparé
    private void Listening()
    {
      SocketError error;
      while (runing)
      {
         Socket.Receive(tmpReceive, 0, MaxSizeReceive, SocketFlags.None, out error);
         ReadPacket(tmpReceive);
      }
    }
    Fermeture :
    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
    public void Close()
    {
       if (Socket == null)
         return;
     
       runing = false;
       WaitForMessageToSend.Set();
     
     
       lock (Socket)
       {
          Socket.Shutdown(SocketShutdown.Both);
          Socket.Close();
       }
    }
    Ca marche bien, mais le problème est qu'au moment de l'appelle à Socket.Close, Il me déclenche uyne exception à Socket.Receive

    Quelqu'un connaitrai la solution ?

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Il y a un overload de Close qui prend en paramètre un timeout. En jouant sur ça et sur le ReceiveTimeout de la socket, tu peux peut-être arriver à quelque chose...

Discussions similaires

  1. Utilisation des Socket
    Par Bull_ dans le forum C++
    Réponses: 4
    Dernier message: 11/03/2007, 15h48
  2. [c#] Utilisation des sockets
    Par zwoke dans le forum Windows Forms
    Réponses: 1
    Dernier message: 28/09/2006, 09h28
  3. [Socket][C++]Utilisation des sockets sur internet
    Par ChriGoLioNaDor dans le forum Développement
    Réponses: 8
    Dernier message: 13/01/2006, 21h38
  4. [MFC] Faible utilisation des sockets via les MFC ?
    Par Yellowmat dans le forum MFC
    Réponses: 1
    Dernier message: 25/08/2005, 17h15
  5. utilisation des sockets sous windows
    Par Tupac dans le forum Réseau
    Réponses: 2
    Dernier message: 21/12/2002, 18h24

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