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

Réseau C Discussion :

Probleme recv() bloquant


Sujet :

Réseau C

  1. #1
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    302
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 302
    Par défaut Probleme recv() bloquant
    Bonjour,
    Je dois developper une DLL qui va s'occuper de gerer une communication avec un serveur.

    Mon probleme est que cette dll doit etre parcourue (enfait j'inclus cette dll dans un vi labView qui tourne en boucle).

    Mais comme la fonction recv() est bloquante, ca peut etre planter mon programme a partir du moment ou cette fonction ne recoit rien et ca ne peut pas se passer ...

    J'ai vu qu'il existait plusieurs moyen de regler le probleme ... Soit utiliser des thread, soit utiliser la fonction select ou alors rendre le socket non bloquant ...
    J'aurai besoin de votre avis (et voir d'une explication par la suite) pour savoir qu'elle solution semble la meilleur et par après comment la mettre en place ...

    Merci d'avance pour votre aide

    (ps: si besoin est, je peux vous poster le code déjà écrit)

  2. #2
    Membre confirmé
    Profil pro
    Responsable de projet
    Inscrit en
    Décembre 2005
    Messages
    97
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Responsable de projet

    Informations forums :
    Inscription : Décembre 2005
    Messages : 97
    Par défaut
    Ben ouai essaye avec les thread ça a l'air pas mal comme solution ça.

  3. #3
    Membre émérite Avatar de |PaRa-BoL
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 738
    Par défaut
    Pour rendre le file descriptor non bloquant :

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    old_flags = fcntl(fd, F_GETFL, 0);
    if (!(old_flags & O_NONBLOCK)) {
         old_flags |= O_NONBLOCK;
    }
    fcntl(fd, F_SETFL, old_flags);

    Après la solution que je préfère est poll() (select un peu plus poussé mais moins portable)

  4. #4
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    302
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 302
    Par défaut
    Voila le probleme qui me vient a l'esprit ...
    c'est le principe du client / serveur !

    Dans mon cas, le client envoie une demande au serveur, le serveur lui répond (classique) ...

    Dans le cas ou le client enverait une demande et que le serveur ne répond pas, cela veut dire qu'il y a un probleme au niveau serveur ou tout simplement le cable réseaux.

    Et donc avec les thread ... La fonction recv() serait excecutée en parallèle et donc la fonction send() pourrait continuer a envoyer des messages ... Hors ca ne sert a rien puisque l'on a pas recu la réponse en retour ...

    Comment puis je agencer mon programme pour palier a ce probleme ?

  5. #5
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    302
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 302
    Par défaut
    |PaRa-BoL :
    Après mur reflexion, je pense que rendre le socket non bloquant pour ne pas qu'il boucle a sur la fonction recv() s'il ne recoit pas de message, n'est pas une solution sécurisée ... Parce que l'on est obligé de recevoir une réponse après avoir fait un send ... C'est juste que si le serveur plante il ne faut pas que ca boucle a l'infini sur recv() ...

  6. #6
    Membre émérite Avatar de |PaRa-BoL
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 738
    Par défaut
    Heu... d'où l'intérêt de select() ou poll(). La documentation à ce sujet est largement répandu ...

    Cela permet justement d'éviter d'utiliser des thread.

    Parce que l'on est obligé de recevoir une réponse après avoir fait un send
    A bon ?

  7. #7
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    302
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 302
    Par défaut
    Xcusez moi ... Mais c'est ma premiere expérience dans le developpement d'une DLL pour une communication avec un serveur.

    Donc j'ai un peu de mal ...

    Dans un cas ou j'envoie plusieurs données différentes et que je peux en recevoir différentes aussi ...

    Les thread ne serait pas un moyen de simplifier le code ?

    Parce qu'avec le select, je devrais l'appeler a chaque fois que j'appelle ma fonction recv() ?
    Citation:
    Parce que l'on est obligé de recevoir une réponse après avoir fait un send

    A bon ?
    Dans mon cas ui ....

  8. #8
    Membre éclairé Avatar de _SamSoft_
    Profil pro
    Étudiant
    Inscrit en
    Février 2007
    Messages
    798
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2007
    Messages : 798
    Par défaut
    Dans le cas de son logiciel sûrement. Au mieux tu prends la solution de |Para-bol sinon, tu peux aussi faire un petit timer pour ne pas faire une boucle trop longtemps ou utiliser les threads.

  9. #9
    Membre émérite Avatar de |PaRa-BoL
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 738
    Par défaut
    L'avantage de poll() est qu'il bloque si aucun file descriptor n'a de données à recevoir. Donc tu n'auras pas de boucle qui fera saturer ton CPU. Et dans le cas où la connexion est rompu il suffit de supprimer le file descriptor de poll().

    Tout ça en gérant les timeout, etc...

  10. #10
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    302
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 302
    Par défaut
    Dans un cas ou j'envoie plusieurs données différentes et que je peux en recevoir différentes aussi ...

    Donc plusieurs appelle différent a la fonction send recv a plusieurs endroit du code ...

    Code C : 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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
     
    // ********************************************************
    // LAFonction
    // ********************************************************
    __declspec(dllexport) void LAfonction(char *ip_adr, unsigned short port){
     
      int prob;
      pthread_t thread;// On crée un thread
     
      //Step = 0 -> Initialisation + connection.
      if(step == 0){
        prob = connection(ip_adr, port);
        if(prob == 0)
          step = 1;
        if(prob == 1)
          step = 3;
      }
     
      //Step = 1 -> Recuperer tout les parametres.
      if(step == 1){        
      }
     
      //Step = 2 -> Envoyer et recevoir des données normalement.
      if(step == 2){
      }
     
      //Step = 3 -> Deconnection.
      if(step == 3){
        close(); 
      }
      /*
      //Step = 4 ->
      if(step == 4){
      printf("ByeBye");
      }
      */                    
    }
     
     
    // ********************************************************
    // Fonctions Connection
    // ********************************************************
    int connection(char *ip_adr, unsigned short port){
      int prob;
      // Initialisation de Winsock
      erreur = WSAStartup(MAKEWORD(2,2), &initialisation_win32);
      if (erreur != 0){
        printf("\nJe ne peux pas initialiser Winsock du a l'erreur : %d %d", erreur, WSAGetLastError());
        prob = 1;
        stepCon = 1;
      }
      else
        printf("\nWSAStartup  : OK");
     
      // Ouverture d'une Socket
      idSocket = socket(AF_INET, SOCK_STREAM, 0);
      if (idSocket == INVALID_SOCKET){
        printf("\nJe ne peux pas creer la socket du a l'erreur : %d", WSAGetLastError());
        prob = 1;
        stepCon = 2;
      }
      else
        printf("\nSocket      : OK");
     
      // Etablissement de l'ouverture de session
      infoServeur.sin_family = AF_INET;
      infoServeur.sin_addr.s_addr = inet_addr(ip_adr); // Indiquez l'adresse IP de votre serveur  
      infoServeur.sin_port = htons(port); // Port écouté du serveur 
      erreur = connect(idSocket, (struct sockaddr*)&infoServeur, sizeof(infoServeur));
      if (erreur != 0){
        printf("\nJe n'ai pas pu ouvrir la session TCP : %d %d", erreur, WSAGetLastError());
        prob = 1;
        stepCon = 3;
      }
      else{
        printf("\nConnect  : OK");
        prob = 0;
        stepCon = 4;
      }
      return prob;
    }
     
    // ********************************************************
    // Fonctions Send
    // ********************************************************
    int sending(char *buffer){
      nbCaractere = send(idSocket, buffer, strlen(buffer), 0);
      if (nbCaractere == SOCKET_ERROR){
        printf("\nJe n'ai pas envoyer les donnees du a l'erreur : %d", WSAGetLastError());
        return 1;
      }
      else{
        printf("\nSend        : OK");
        return 0;
      }  
    }
     
    // ********************************************************
    // Fonction Receive
    // ********************************************************
    void receive(void){
      nbCaractere = recv(idSocket, recbuf, sizeof(recbuf)-1, 0);
      if (nbCaractere==SOCKET_ERROR){
        printf("\nJe n'ai pas recu de donnee");
      }    
      else{
        recbuf[nbCaractere]='\0'; // Permet de fermer le tableau après le contenu des data, car la fonction recv ne le fait pas
        printf("\nReceive     : OK");
      }
    }
     
    // ********************************************************
    // Fonctions Close
    // ********************************************************
    void close(void){
     
      // Fermeture de la session TCP Correspondant à la commande connect()
      if(stepCon == 3 || stepCon == 4){
        erreur = shutdown(idSocket, 2); // 2 signifie socket d'émission et d'écoute
        if (erreur != 0){
          printf("\nJe ne peux pas fermer la session TCP du a l'erreur : %d %d", erreur, WSAGetLastError());
        }
        else{
          printf("\nShutdown    : OK");
        }
      }
     
      // Fermeture de la socket correspondant à la commande socket()
      if(stepCon == 2 || stepCon == 4){
        erreur = closesocket(idSocket);
        if (erreur != 0){
          printf("\nJe ne peux pas liberer la socket du a l'erreur : %d %d", erreur, WSAGetLastError());
        }
        else{
          printf("\nClosesocket : OK");
        }
      }
     
      // Quitte proprement le winsock ouvert avec la commande WSAStartup
      if(stepCon == 1 || stepCon == 4){
        erreur = WSACleanup(); // A appeler autant de fois qu'il a été ouvert.
        if (erreur != 0){
          printf("\nJe ne peux pas liberer winsock du a l'erreur : %d %d", erreur, WSAGetLastError());
        }
        else{
          printf("\nWSACleanup  : OK");
        }
      }
    }

    On passe a travers de LAFonction ...

    Les thread ne serait pas un moyen de simplifier le code ?

  11. #11
    Membre émérite Avatar de |PaRa-BoL
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 738
    Par défaut
    Qui dit thread dit accès concurrent à la mémoire donc MuTeX, priorités, synchronisations, etc... Donc plus simple je ne pense pas

  12. #12
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    302
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 302
    Par défaut
    En plus après mur reflexion ... la fonction poll ou select ... Je n'ai qu'a l'appliquer une fois dans ma fonction d'envoi de message ...

    (si j'ai bien compris )

  13. #13
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    302
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 302
    Par défaut Code
    Bonjour ... Voila, j'ai essayé d'implementer l'idée du select ... Mon code compile mais je me demandais si vous pouviez jeter un oeil pour voir si cela correspond bien a l'idée et si ca sera fonctionelle :

    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
     
    // ********************************************************
    // Fonction Receive
    // ********************************************************
    void receive(void){
     
      int sel;
      fd_set read;
      struct timeval timeout;
     
      timeout.tv_sec = 0;
      timeout.tv_usec = 10000;
     
      FD_ZERO(&read);
      FD_SET(idSocket, &read);
     
      sel = select(idSocket + 1, &read, NULL, NULL, &timeout);
      if(sel == SOCKET_ERROR){
        printf("\nJe n'ai pas su faire le select");
      }
      else if(sel == 0){
        printf("\nLe serveur est probablement mort");
        printf("\nDeconnection");
        step = 3;
      }
      else{
        if(FD_ISSET(idSocket, &read)){     
          nbCaractere = recv(idSocket, recbuf, sizeof(recbuf)-1, 0);
          if (nbCaractere==SOCKET_ERROR){
    	printf("\nJe n'ai pas recu de donnee");
          }    
          else{
    	recbuf[nbCaractere]='\0'; // Permet de fermer le tableau après le contenu des data, car la fonction recv ne le fait pas
    	printf("\nReceive     : OK");
          }
        }
      }
    }
    Autre question, est ce qu'il est preferable de declarer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
      int sel;
      fd_set read;
      struct timeval timeout;
     
      timeout.tv_sec = 0;
      timeout.tv_usec = 10000;
    Dans ma fonction, ou bien en variable accessible de partout ... comme ca elle ne serait declarée qu'une fois et pas a chaque appelle de la fonction ...?

  14. #14
    Membre éclairé Avatar de _SamSoft_
    Profil pro
    Étudiant
    Inscrit en
    Février 2007
    Messages
    798
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2007
    Messages : 798
    Par défaut
    variable accessible de partout
    Les globales dans la majorité des cas c'est mal (99% hein ?).

    Si tu as vraiment besoin de la valeur de la variable dans un tas de fonction, passe la en paramètre.

  15. #15
    Membre émérite Avatar de |PaRa-BoL
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 738
    Par défaut
    Les globales dans la majorité des cas c'est mal (99% hein ?).
    Pas très constructif de dire ca Tout dépend du contexte...

  16. #16
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    302
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 302
    Par défaut
    SInon au nivo du code, ca vous semble correcte ?

    Et donc ok, je vais eviter au max de mettre les variables en global ...

    Merci de votre aide

  17. #17
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 69
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par |PaRa-BoL Voir le message
    Pour rendre le file descriptor non bloquant :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    old_flags = fcntl(fd, F_GETFL, 0);
    if (!(old_flags & O_NONBLOCK)) {
         old_flags |= O_NONBLOCK;
    }
    fcntl(fd, F_SETFL, old_flags);
    Pas portable.

  18. #18
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    302
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 302
    Par défaut
    Et est ce que le code que j'ai posté est portable ?

  19. #19
    Membre émérite Avatar de |PaRa-BoL
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 738
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     erreur = WSAStartup(MAKEWORD(2,2), &initialisation_win32);
    Non...

  20. #20
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 69
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par |PaRa-BoL Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     erreur = WSAStartup(MAKEWORD(2,2), &initialisation_win32);
    Non...
    Bah, ill suffit d'ignorer si on est pas en win32... La compilation conditionnelle est faite pour ça...

    http://emmanuel-delahaye.developpez....#projet_reseau

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Probleme recevfrom bloquante
    Par LinuxUser dans le forum Réseau
    Réponses: 2
    Dernier message: 09/12/2008, 13h45
  2. probleme recv() et send() client/serveur
    Par romainromain dans le forum Réseau
    Réponses: 2
    Dernier message: 18/12/2006, 20h13
  3. Probleme recv() [Winsock]
    Par kernox dans le forum Réseau
    Réponses: 3
    Dernier message: 11/04/2006, 21h58
  4. Probleme lors du recv TCP
    Par MonsieurAk dans le forum Développement
    Réponses: 3
    Dernier message: 10/01/2006, 16h56
  5. Réponses: 2
    Dernier message: 31/05/2005, 10h50

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