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 :

Fonction select() les données ne s'envoient que lors d'un recv !


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de theclem35
    Homme Profil pro
    Technicien Réseaux & Télécommunications
    Inscrit en
    Décembre 2007
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Technicien Réseaux & Télécommunications
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2007
    Messages : 148
    Par défaut Fonction select() les données ne s'envoient que lors d'un recv !
    Salut !

    Voila j'utilise la fonction select pour ne pas bloquer sur un recv lors d'une connexion TCP.
    Tout cela fonctionne parfaitement, je recoie uniquement quand le client envoie.

    Le probleme c'est à l'inverse quand moi je veux envoyer des données, il n'y a rien qui sort tant que je n'ai pas recu de données....

    Pourtant j'ai bien placé mon send à l'exterieur du if(FD_ISSET... donc le send devrait s'executer a chaque tour de boucle..

    Voici le bout de code (juste la boucle) :
    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
    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
          do
          {
     
               FD_ZERO(&EnsembleLecture); // A chaque tour de boucle on remet a zero l'ensemble
               FD_SET(StructureEchangee->IDSocketClient, &EnsembleLecture); // On met l'id de la socket client dans l'emnsemble de lecture
     
               CodeErreur = select(StructureEchangee->IDSocketClient + 1, &EnsembleLecture, NULL, NULL, NULL); // On vérifie s'il y a des données dans la socket
               if (CodeErreur < 0)
               {
                   sprintf(TexteErreur,"Impossible de faire un select sur la socket client du à l'erreur : %d",WSAGetLastError());
                   MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                   return -1;
               }
     
               if(FD_ISSET(StructureEchangee->IDSocketClient, &EnsembleLecture)) // Si il y a des données dans la socket
               {
                    MessageBox(NULL,"select : il y a des donnees","Erreur Générale !",MB_OK | MB_ICONERROR);
                    LongueurMessage = recv(StructureEchangee->IDSocketClient, (char*)&StructRecue, sizeof(StructSocket),0); // On recoit la position
                    if (LongueurMessage == SOCKET_ERROR)
                    {
                        sprintf(TexteErreur,"serv: Impossible de recevoir les données du à l'erreur : %d",WSAGetLastError());
                        MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                        closesocket(StructureEchangee->IDSocketClient);
                        closesocket(StructureEchangee->IDSocketServeur);
                        return -1;
                    }
     
                    StructureEchangee->PositionJoueurDistant = StructRecue.PositionJoueurLocal; // On met la position du joueur distant dans notre structure locale
     
                    if(LongueurMessage == 0) // Recv vaut 0 si on a recu un shutdown
                    {
                        StructureEchangee->ActiverTransmission = FALSE; // A notre tour on desactive la transmission ce qui va envoyer un shutdown dans le thread d'emission
                        sleep(2000); // On fait une pause de 1s avant de sortir de la boucle car sinon on ferme la socket avant d'envoyer le shutdown (thread d'envoi)
                    }   
                }
     
      //          if((StructureEchangee->PositionJoueurLocal.x != PositionJLocalPrecedente.x) || (StructureEchangee->PositionJoueurLocal.y != PositionJLocalPrecedente.y) || (!StructureEchangee->ActiverTransmission))
       //         { // Si notre position a changé, ou si on recoit une demande d'arret de transmission de l'application principale
     
                     LongueurMessage = send(StructureEchangee->IDSocketClient, (char*)StructureEchangee, sizeof(StructSocket),0);
                     sprintf(TexteErreur,"serv: longeur envoi : %d",LongueurMessage);
                         MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONWARNING);
                     if (LongueurMessage == SOCKET_ERROR)
                     {
                         sprintf(TexteErreur,"serv: Impossible d'envoyer les données du à l'erreur : %d",WSAGetLastError());
                         MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                         return -1;
                     }
     
                     if(!StructureEchangee->ActiverTransmission) // Si on doit arreter la transmission
                     {
                          CodeErreur = shutdown(StructureEchangee->IDSocketClient, 1); // On shutdown les operations sur la socket puisqu'on a 500ms de delai
                          sprintf(TexteErreur,"serv: valeur shutdown : %d",CodeErreur);
                         MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONWARNING);
                          if (LongueurMessage == SOCKET_ERROR)
                          {
                               sprintf(TexteErreur,"Impossible de shutdown la socket du a l'erreur : %d",WSAGetLastError());
                               MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                               return -1;
                          }
                     }
                     else
                     {
                         PositionJLocalPrecedente.x = StructureEchangee->PositionJoueurLocal.x; // On remplace la position precedente par la position actuelle
                         PositionJLocalPrecedente.y = StructureEchangee->PositionJoueurLocal.y; // Ca evite d'envoyer des paquets alors qu'on ne bouge pas
                     }
     
     
          //      }
     
          } while (LongueurMessage != 0); // Shutdown terminé dans les deux sens, on ferme proprement les sockets
    Merci!

  2. #2
    Invité
    Invité(e)
    Par défaut Select est bloquant
    Bonjour,

    ton problème vient du fait que select soit bloquant par default : tant qu'il ne se passe rien sur les fd qu'elle surveille, elle stoppe le processus. Comme tu ne lui donne que des fd en lecture à surveiller, et aucun timeout, elle bloquera tant que tu ne recevras rien à lire.

    Pour obtenir le comportement que tu souhaites, tu as deux solutions :
    1) definir le temps maximum pendant lequel tu souhaites que select bloque. Pour cela, il faut utiliser le dernier argument de select, qui utilise une structure timeval.

    2) lui dire de surveiller les fd en écriture que tu souhaites utiliser, en lui envoyant un fd_set en troisième argument. Dans ce cas, select sortira de sa boucle dès que le fd sera prêt en écriture. Dans la majorité des cas, les fd sont toujours prêts, et select ne bloquera quasiment pas la boucle, ce lui fait perdre une grande partie de son intérêt. Tu ne dois donc lui donner à surveiller des fd en écriture que si tu as des données à écrire.

    Dis-moi si tu as besoin de précisions,
    Nathan

  3. #3
    Membre confirmé Avatar de theclem35
    Homme Profil pro
    Technicien Réseaux & Télécommunications
    Inscrit en
    Décembre 2007
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Technicien Réseaux & Télécommunications
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2007
    Messages : 148
    Par défaut
    Oui effectivement car je ne vois pas comment lui envoyer un message *Localement* que j'ai besoin d'écrire sur la socket.

    En fait j'ai uniquement besoin d'écrire dans ce cas la :
    StructureEchangee->PositionJoueurLocal.x != PositionJLocalPrecedente.x) || (StructureEchangee->PositionJoueurLocal.y != PositionJLocalPrecedente.y)

    C'est à dire si je change au clavier la position de mon bonhome.

    Mais étant donné que la fonction select bloque, je ne vois pas comment faire ce if, mis à part dans un autre thread, dans ce cas la auant mettre la fonction send dans l'autre thread..

  4. #4
    Invité
    Invité(e)
    Par défaut
    Je ne vois pas le problème, j'ai du mal comprendre :

    Puisque tu lis la structure à chaque tour de boucle, tu sais si ta condition est remplie avant d'entrer dans le select. Dès lors :

    - tu déclares un fd_set pour les fd en écritures, que tu mets à FD_ZERO
    - tu effectues la lecture et traite l'information
    - si la condition est réalisée, tu fais un FD_SET en ecriture
    - sinon tu ne le fais pas.

  5. #5
    Membre confirmé Avatar de theclem35
    Homme Profil pro
    Technicien Réseaux & Télécommunications
    Inscrit en
    Décembre 2007
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Technicien Réseaux & Télécommunications
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2007
    Messages : 148
    Par défaut
    Oui mais justement le select me bloque dans ma boucle.

    Imaginos que je ne recoive pas de données.
    Je suis donc bloqué sur le select.
    Maintenant je bouge mon bonhome avec le clavier.
    Je veux que sa position soit envoyée, sauf qu'il n'y a aucun moyen de le faire puisque je suis toujours bloqué sur mon select!

    Donc c'est meme pas le problème d'envoyer, un simple test est impossible du fait du blocage !

    Ou alors je n'ai pas compris ce que tu as voulu dire

  6. #6
    Invité
    Invité(e)
    Par défaut
    Donc en fait ton problème est dans le client, pas dans le serveur ? J'avais compris le contraire

    Dans ce cas, ouvre le fd en mode non bloquant, je cite le man : If no messages are available at the socket and O_NONBLOCK is set on the socket's file descriptor, recv() shall fail and set errno to [EAGAIN] or [EWOULDBLOCK].

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] récupérer les données d'un fichier que l'on sélectionne
    Par olivier59820 dans le forum MATLAB
    Réponses: 2
    Dernier message: 28/06/2011, 14h57
  2. Réponses: 5
    Dernier message: 23/06/2009, 00h10
  3. [XL-2003] Comment utiliser la fonction "Actualiser les données"
    Par P96O1004 dans le forum Excel
    Réponses: 10
    Dernier message: 27/05/2009, 15h05
  4. Fonction garde les donnés des call précédent.. que faire?
    Par tux94 dans le forum Programmation et administration système
    Réponses: 0
    Dernier message: 02/04/2008, 15h56
  5. Réponses: 2
    Dernier message: 24/04/2007, 21h04

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