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 :

Sockets dans un thread, mais application toujours bloquée..


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 Sockets dans un thread, mais application toujours bloquée..
    Salut!

    Voila j'utilise les sockets dans mon application et comme j'ai des fonctions bloquantes (recvfrom) j'ai placé tout ca dans un thread.

    Maitenant quand je clique sur mon bouton j'appelle le thread.

    Seul problème c'est que mon appli reste figée, mon bouton enfoncé !
    Bref aucune difference par rapport a avec ou sans thread !

    Pouvez vous m'aider ?

    Le code de mon thread (enfin juste le début car après c'est les sockets..) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    DWORD WINAPI HebergementPartie(void * thPartie) // Avec un thread on a un type void * (on peut mettre ce qu'on veut)
    {
          InfosPartie * PartieCree = thPartie; // On indique qu'on veut travailler sur une structure InfosPartie pour notre variable e/s
    [....] // Le reste du code ...
    Mon appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        InfosPartie MaPartie;
        HANDLE hdlThreadServeur;
        DWORD CodeRetourThread;
     
                   hdlThreadServeur = CreateThread(NULL, 0, HebergementPartie, &MaPartie, 0, NULL); // On lance le thread pour une ecoute UDP en attente de demande d'infos, ou de connexion
                   // faire une animation d'attente
                   WaitForSingleObject(hdlThreadServeur, INFINITE); // On attend que le thread se finisse naturellement
                   GetExitCodeThread(hdlThreadServeur, &CodeRetourThread); // Puis on recupere le code de retour du thread
                   if(CodeRetourThread != -1)
                   {
                         // On ferme toutes les fenetres et on demarrer la partie
                   }
    Je vois pas trop ce qui coche !

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Salut

    Il y a bien trop peu de code pour qu'on puisse répondre.

  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
    Coucou! Oui j'ai mis le principal car le reste n'a rien avoir et fonctionne parfaitement.

    Voila pour plus de details :

    Ma fonction hebergementPartie :
    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
    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
    DWORD WINAPI HebergementPartie(void * thPartie) // Avec un thread on a un type void * (on peut mettre ce qu'on veut)
    {
          InfosPartie * PartieCree = thPartie; // On indique qu'on veut travailler sur une structure InfosPartie pour notre variable e/s
          int CodeErreur; // Code d'erreur des fonctions
          int ReponseConnexion;
          int TailleStructure; // Taille de la structure serveur
          char TexteErreur[120]; // Pour insérer le message d'erreur des socket dans la msgbox
          int LongueurMessage; // Nombre de caracteres
          char Tampon[65535]; // Tampon pour les données reçues ou envoyées
          SOCKET idSocket; // Identifiant de la socket
          SOCKADDR_IN InfosServeur, InfosClient; // Structure contenant les infos du serveur
     
          idSocket = socket(AF_INET,SOCK_DGRAM,0); // On ouvre la socket en UDP
          if (idSocket == INVALID_SOCKET)
          {
                   sprintf(TexteErreur,"Impossible de creer la socket du à l'erreur : %d",WSAGetLastError());
                   MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                   return -1; // On termine la fonction et renvoi -1 pour prevenir l'appli principale
          }
     
          /* Config Infos Serveur */  
          InfosServeur.sin_family = AF_INET;
          InfosServeur.sin_addr.s_addr = INADDR_ANY; // Ecoute sur toutes les IPs 
          InfosServeur.sin_port = htons(PORT_SERVICE_SERVEUR); // Ecoute sur le port 1337
          /* ******************* */
     
          CodeErreur = bind(idSocket,(struct sockaddr*)&InfosServeur,sizeof(InfosServeur)); // On bind la socket
          if (CodeErreur != 0)
          {
                sprintf(TexteErreur,"Impossible d'écouter ce port du à l'erreur : %d",WSAGetLastError());
                MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                closesocket(idSocket);
                return -1;
          }
     
          TailleStructure = sizeof(InfosServeur); // Taille de la structure car pointeur dans le recvfrom
     
          while(1)
          {
                  LongueurMessage = recvfrom(idSocket,Tampon,1515,0,(struct sockaddr*)&InfosClient,&TailleStructure);
                  if (LongueurMessage == SOCKET_ERROR)
                  {
                         sprintf(TexteErreur,"Impossible de recevoir les données du à l'erreur : %d",WSAGetLastError());
                         MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                         closesocket(idSocket);
                         return -1;
                  }
                  Tampon[LongueurMessage] = 0; // On rajoute \0 pour fermer la chaine
     
                  if(!strcmp(Tampon, "DECOUVERTE")) // On envoie la structure de la partie créée et on continue à écouter
                  { 
                         LongueurMessage = sendto(idSocket, (char*)PartieCree, sizeof(InfosPartie),0,(struct sockaddr*)&InfosClient,TailleStructure);
                         if (LongueurMessage == SOCKET_ERROR)
                         {
                                 sprintf(TexteErreur,"Impossible d'envoyer les données du à l'erreur : %d",WSAGetLastError());
                                 MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                                 closesocket(idSocket);
                                 return -1;
                         }
     
                  }
                  else if(!strcmp(Tampon, "CONNEXION"))
                  {                
                         sprintf(TexteErreur,"Le client avec l'IP %s a demandé à se connecter\nAccepter ?",inet_ntoa(InfosClient.sin_addr));
                         ReponseConnexion = MessageBox(NULL,TexteErreur,"Connexion entrante",MB_YESNO | MB_ICONQUESTION); // Messagebox avec oui/non sous forme de question
     
                         if (ReponseConnexion == 6) // Si on accepte le client (OUI vaut 6)
                         {
                                 strcpy(Tampon,"CONNEXIONACCEPTEE"); // Copie la chaine de caractère dans buffer
                                 LongueurMessage = sendto(idSocket,Tampon,strlen(Tampon),0,(struct sockaddr*)&InfosClient,sizeof(InfosClient)); // On envoie la sequence CONNACCEPT pour accepter la client
                                 if (LongueurMessage == SOCKET_ERROR)
                                 {
                                         sprintf(TexteErreur,"Impossible d'envoyer les données du à l'erreur : %d",WSAGetLastError());
                                         MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                                         closesocket(idSocket);
                                         return -1;
                                 }
     
                                 LongueurMessage = recvfrom(idSocket,Tampon,1515,0,(struct sockaddr*)&InfosClient,&TailleStructure); // On recoit le nom du joueur2 pour remplir la structure
                                 if (LongueurMessage == SOCKET_ERROR)
                                 {
                                        sprintf(TexteErreur,"Impossible de recevoir les données du à l'erreur : %d",WSAGetLastError());
                                        MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                                        closesocket(idSocket);
                                        return -1;
                                 }
                                 Tampon[LongueurMessage] = 0; // On rajoute \0 pour fermer la chaine
     
                                 strcpy(PartieCree->PseudoJ2, Tampon); // On rempli la structure avec le pseudo du Joueur 2
                                 strcpy(PartieCree->IPClient, inet_ntoa(InfosClient.sin_addr)); // SOn adresse IP ...
     
                                 break; // ... On a toutes les infos, on arrete l'ecoute UDP et on passe en TCP pour la partie
                         }
                         else
                         {
                                 strcpy(Tampon,"CONNEXIONREFUSEE"); // Copie la chaine de caractère dans buffer
                                 LongueurMessage = sendto(idSocket,Tampon,strlen(Tampon),0,(struct sockaddr*)&InfosClient,sizeof(InfosClient)); // On envoie la sequence REFUSER pour refuser le client
                                 if (LongueurMessage == SOCKET_ERROR)
                                 {
                                         sprintf(TexteErreur,"Impossible d'envoyer les données du à l'erreur : %d",WSAGetLastError());
                                         MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                                         closesocket(idSocket);
                                         return -1;
                                 } 
                         }
                  }
          }
     
          CodeErreur = closesocket(idSocket); // On ferme la socket qui a été ouverte
          if (CodeErreur != 0)
          {
                sprintf(TexteErreur,"Impossible de libérer la socket du à l'erreur : %d",WSAGetLastError());
                MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                return -1;
          }
     
          return 0; // Tout s'est bien passé
    }
    Et la fonction qui gere mon bouton :
    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
    void GestBoutonsFHebergerPartie(HWND fenetre,UINT message, WPARAM wParam, LPARAM lParam)
    {
        char NomPartie[256],PortSaisi[6],NomJoueur1[13],IPChoisie[16],NiveauChoisi[3];
        int PortConverti;
        InfosPartie MaPartie;
        HANDLE hdlThreadServeur;
        DWORD CodeRetourThread;
     
        switch(LOWORD(wParam)) // Quand btn enfoncé, une partie de wParam vaut Id du bouton => recup avec LOWORD()
        {
        case ID_LANCER_SERVEUR:
             GetDlgItemText(fenetre, ID_NOM_PARTIE, NomPartie, 23); // On recupere toutes les valeurs entree par le joueur
             GetDlgItemText(fenetre, ID_COMBOBOX_LISTEIPS, IPChoisie, 16);
             GetDlgItemText(fenetre, ID_PORT_CHOISI, PortSaisi, 6);
             GetDlgItemText(fenetre, ID_COMBOBOX_LISTENIVEAUX, NiveauChoisi, 3);
             GetDlgItemText(fenetre, ID_PSEUDO_JOUEUR1, NomJoueur1, 13);
             sscanf(PortSaisi, "%d", &PortConverti); // Obligé de faire une conversion char->int pour tester si le port est correct
     
             if((PortConverti < 1025) || (PortConverti > 65535))
             {
                   MessageBox(NULL,"Le port doit être compris entre 1024 et 65535 !","Erreur !",MB_OK | MB_ICONWARNING);
             }
             else if(NomPartie[0] == '\0') // On teste si le 1er caractere est une fin de chaine, autrement dit si elle est nulle
             {
                   MessageBox(NULL,"Veuillez spécifier un nom pour votre partie...","Erreur !",MB_OK | MB_ICONWARNING);
             }
             else if(NomJoueur1[0] == '\0')
             {
                   MessageBox(NULL,"Veuillez spécifier votre pseudo !","Erreur !",MB_OK | MB_ICONWARNING);
             }
             else
             {
                   strcpy(MaPartie.NomPartie, NomPartie); // On remplie la structure qu'on enverra sur le reseau en reponse aux broadcasts
                   strcpy(MaPartie.IPServeur, IPChoisie);
                   strcpy(MaPartie.Port, PortSaisi);
                   strcpy(MaPartie.Niveau, NiveauChoisi);
                   strcpy(MaPartie.PseudoJ1, NomJoueur1);
     
                   // probabilité d'erreur sur taille de la structure Partie en (char *) dans sockets alors que pointeur
     
                   hdlThreadServeur = CreateThread(NULL, 0, HebergementPartie, &MaPartie, 0, NULL); // On lance le thread pour une ecoute UDP en attente de demande d'infos, ou de connexion
                   // faire une animation d'attente
                   WaitForSingleObject(hdlThreadServeur, INFINITE); // On attend que le thread se finisse naturellement
                   GetExitCodeThread(hdlThreadServeur, &CodeRetourThread); // Puis on recupere le code de retour du thread
                   if(CodeRetourThread != -1)
                   {
                         // On ferme toutes les fenetres et on demarrer la partie
                   }
             }
            break;
        case ID_QUITTER_HEBERGEMENT:
            ShowWindow(fenetre, SW_HIDE);
            break;
        }
    }
    En fait on dirait (on dirait seulement) que c'est ma fonction WaitForSingleObject(hdlThreadServeur, INFINITE); qui bloque mon programme alors que normalement les threads sont faits pour eviter ca !
    Je ne comprend pas ce qui se passe.

  4. #4
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Apparemment, GestBoutonsFHebergerPartie est la fonction callback de ta fenêtre, qui gère les événements (clic bouton sur tel bouton, ...). Si tu lances un autre thread et que tu bloques le thread principal avec un WaitForSingleObject, c'est normal que plus rien ne réagisse, puisque les messages Windows (gestion clics, redimensionnement, rafraichissement, etc) ne peuvent plus être gérés dans la boucle principale (qui, elle aussi, est gelée), ni traités par la fonction callback... et ce jusqu'à ce que le second thread soit terminé.

    EDIT :
    En principe, tu ne dois pas bloquer le thread courant. Le but est justement de faire tourner plusieurs thread. Si tu appuies sur un bouton pour lancer une fonction dans un second thread, tu peux par exemple griser le bouton, le temps que la fonction s'exécute, puis le rendre cliquable une fois que le thread est fini. (Ca dépend ce que tu veux faire)

  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 c'est bien la fonction callback (enfin du moins celle qui gere les WM_COMMAND)

    Du coup comment faire pour mettre mes sockets dans un autre thread sans bloquer ma fenetre principale ?
    Dans ce que tu as dis, j'ai compris que WaitForSingleObject est une fonction bloquante ?????? Du coup aucun interet d'utiliser les threads??????

    Le probleme c'est que si je n'appelle pas WaitForSingleObject et que je lance mon serveur, le port est bien ouvert et il est apparament en ecoute, sauf que j'ai des données complètement incohérente quand je me connecte en client sur le serveur, alors que ca marche très bien d'habitude...

  6. #6
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Le probleme c'est que si je n'appelle pas WaitForSingleObject et que je lance mon serveur, le port est bien ouvert et il est apparament en ecoute, sauf que j'ai des données complètement incohérente quand je me connecte en client sur le serveur, alors que ca marche très bien d'habitude...
    Oui, car il y a un gros soucis dans ton code : les variables locales à ta fonction callback. Lorsqu'un message Windows est choppé par la boucle principale, la fonction callback est lancée, puis on quitte, et on retourne dans la boucle. Or, tu envoies à ton second thread l'adresse d'un objet local à ta fonction callback... qui est détruit juste après.

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

Discussions similaires

  1. [WD15] WaitForMultipleObjects dans un thread bloque mon application
    Par peijnoob dans le forum WinDev
    Réponses: 1
    Dernier message: 22/04/2010, 11h39
  2. fermeture socket dans un thread
    Par adrien1 dans le forum Débuter
    Réponses: 0
    Dernier message: 20/04/2010, 14h45
  3. Probleme de socket dans un thread
    Par nikus dans le forum Threads & Processus
    Réponses: 4
    Dernier message: 25/06/2008, 03h27
  4. problème de socket dans une application win32
    Par deck_bsd dans le forum Windows
    Réponses: 5
    Dernier message: 20/01/2007, 18h32
  5. [Serveur J2EE] Faire tourner un thread dans un serveur d'applications
    Par Pierre-Yves VAROUX dans le forum Java EE
    Réponses: 3
    Dernier message: 13/10/2005, 14h10

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