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 :

Terminer un thread qui a ouvert une socket


Sujet :

C

  1. #1
    Membre régulier 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
    Points : 86
    Points
    86
    Par défaut Terminer un thread qui a ouvert une socket
    Salut!

    Voila j'ai un petit soucis, j'ai un thread avec lequel j'ecoute ce qui arrive sur un port.

    Seulement quand l'utilisateur veut arreter le programme il clique sur un bouton auquel j'ai associé la fonction TerminateThread(hdlThreadServeur,-1);

    Le thread se termine bien, mais le probleme c'est que la socket reste ouverte...
    Et oui j'ai mis un closesocket dans mon thread en cas d'erreur ou de fin d'éxecution normale.

    Le probleme c'est que depuis la fonction ou j'appelle TerminateThread, j'ai pas accès à l'id de la socket ouverte pour pouvoir la fermer (puisqu'elle a été créée dans le thread).
    Et j'ai pas envie de mettre ca en variable globale...

    Y a til une solution pour retrouver l'id d'une socket ouverte, ou bien de dire a mon thread avant de le killer, de fermer la socket ??

    Merci!

  2. #2
    Membre confirmé Avatar de Flow_75
    Femme Profil pro
    Ingénieure
    Inscrit en
    Mai 2005
    Messages
    1 096
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieure
    Secteur : Transports

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 096
    Points : 633
    Points
    633
    Par défaut
    Tu pourrais mettre un bout de ton programme ?

  3. #3
    Membre régulier 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
    Points : 86
    Points
    86
    Par défaut
    Oui :

    Mon thread :
    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
    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(fenetreAnimHebergement,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(fenetreAnimHebergement,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(fenetreAnimHebergement,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(fenetreAnimHebergement,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR);
                return -1;
          }
     
          return 0; // Tout s'est bien passé
    }
    L'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
                   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
     
                   ShowWindow(fenetreHebergerPartie, SW_HIDE); // On ferme notre fenetre d'hebergement
                   ShowWindow(fenetreAnimHebergement, SW_SHOW); // On ouvre l'animation d'attente de client
                   SetTimer(fenetreAnimHebergement, ID_TIMER_HEBERG_PARTIE, 2000, NULL); // Toutes les 2 secondes on envoie un message pour tester si le thread serveur est terminé
    Le timer/traitement de l'annulation :
    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
    LRESULT CALLBACK procedureFenetreAnimHebergement(HWND fenetreAnimHebergement, UINT message, WPARAM wParam, LPARAM lParam)
    {   
        static HWND handleProgressBar; // handle de la progressbar
        DWORD CodeRetourThread; // Code de retour de fin de thread du serveur
     
        if(!handleProgressBar) handleProgressBar = GetDlgItem(fenetreAnimHebergement, ID_PROGRESSBAR_HEBERG);
     
        switch (message)
        {
        case WM_CREATE:
            RemplirFenetreAnimHebergement(fenetreAnimHebergement);
            SendMessage(handleProgressBar, PBM_SETRANGE, 0, MAKELONG(0,22)); // On met une progressbar de rang 22
            SendMessage(handleProgressBar, PBM_SETSTEP, 1, 0); // Configuration du pas à 1
            return 0;
     
        case WM_COMMAND: // Quand un bouton est enfoncé message = WM_COMMAND
            if(LOWORD(wParam) == ID_STOPPER_ECOUTE) // Quand btn enfoncé, une partie de wParam vaut Id du bouton => recup avec LOWORD()
            {
                 KillTimer(fenetreAnimHebergement, ID_TIMER_HEBERG_PARTIE); // On kill le timer
                 TerminateThread(hdlThreadServeur,-1);
     
     
     
     
     
                 /// SOCKET A KILLER !!!!
     
     
     
            }
            return 0;
     
        case WM_TIMER: 
            switch (wParam) 
            { 
                case ID_TIMER_HEBERG_PARTIE: // Toutes les 5 secondes on teste si le thread est terminé
     
                    GetExitCodeThread(hdlThreadServeur, &CodeRetourThread); // On récupère le code de retour du thread
                    SendMessage(handleProgressBar, PBM_STEPIT, 0, 0); // On envoie un carré dans la progressbar
     
                    if(CodeRetourThread == -1)
                    {
                         KillTimer(fenetreAnimHebergement, ID_TIMER_HEBERG_PARTIE); // On kill le timer
                         ShowWindow(fenetreAnimHebergement, SW_HIDE); // On enleve l'attente d'animation
                         ShowWindow(fenetreHebergerPartie, SW_SHOW); // On remet la fenetre de reglage de la partie
                    }
                    else if(CodeRetourThread == 0)
                    {
                         KillTimer(fenetreAnimHebergement, ID_TIMER_HEBERG_PARTIE); // On kill le timer
                         MessageBox(fenetreAnimHebergement,"Infos du client recues, socket fermé\n-> Démarrage de la partie","Tout semble OK...",MB_OK | MB_ICONASTERISK);
                         // On ferme toutes les fenetres et on demarre la partie
                         ShowWindow(fenetreAnimHebergement, SW_HIDE);
                    }
                    return 0; 
            } 
     
        case WM_CLOSE:
            ShowWindow(fenetreAnimHebergement, SW_HIDE); // Fermer fenetre et non detruire
            return 0;
     
        default:
            return DefWindowProc(fenetreAnimHebergement,message,wParam,lParam);
        }
    }

  4. #4
    Membre confirmé Avatar de Flow_75
    Femme Profil pro
    Ingénieure
    Inscrit en
    Mai 2005
    Messages
    1 096
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieure
    Secteur : Transports

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 096
    Points : 633
    Points
    633
    Par défaut
    Je ne sais pas si tu as acces à ta structure

    Lorsque tu veux fermer ton socket, mais tu y a accès alors, tu peux integrer ton socket dedans....

    Le mieux est sans doute de mettre un verrou dans la structure que tu testes à chaque 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
    Thread : 
     
    int boucle (void* p)
    {
    [blabla]
     
    while (PartieCree->Lock == 1)
    {
    [blibli]
    }
     
    closesocket(...);
     
    return 0;
    }

  5. #5
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 81
    Points : 128
    Points
    128
    Par défaut
    TerminateThread est une fonction à utiliser avec précaution.

    Le plus propre serait, à mon avis, de créer un évènement pour demander au thread de se terminer.

    Au niveau du programme principal ou du thread appelant :
    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
     
    enum 
    {
        EVT_KILL,
        /* Définir les autres évènements nécessaires */
        ...
        NB_EVENTS
    };
     
    HANDLE hEvents[NB_EVENTS] = {0};
     
    /* Créer les évènements, le thread et passer tout ça en paramètre pour éviter les globales (à l'aide d'une structure ParamThread à créer, par exemple) */
    ...
     
    /* Démarrer éventuellement l'exécution du thread s'il a été créé avec le flag CREATE_SUSPENDED */
    ResumeThread(hThread);
     
    /* Là, on fait autre chose. On lance d'autres thread ou on rentre dans la boucle principale du programme ou du thread appelant */
    ...
     
    /* Quand on a fini, on demande l'arrêt de notre thread */
    SetEvent(hEvents[EVT_KILL]);
     
    /* On attend l'arrêt du thread */
    WaitForSingleObject(hThread);
    Au niveau du thread à arrêter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
        ...
     
        dwWait = WaitForMultipleObjects(NB_EVENTS, hEvents, FALSE, INFINITE);
     
        if (dwWait == WAIT_OBJECT_0 + EVT_KILL)
        {
             /* Soit on nettoie tout et on quitte, soit on valide la condition de sortie de la boucle principale du thread et on nettoie après */
        }
     
        ...
    Voilà, c'est une possibilité parmi sûrement d'autres.

  6. #6
    Membre régulier 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
    Points : 86
    Points
    86
    Par défaut
    Merci je vais essayer ca

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

Discussions similaires

  1. Arrêter un Thread qui contient juste une JFrame
    Par badich dans le forum Agents de placement/Fenêtres
    Réponses: 9
    Dernier message: 28/06/2013, 16h17
  2. Réponses: 3
    Dernier message: 10/08/2007, 13h42
  3. Arreter un thread qui "bloque" sur un socket
    Par J-F dans le forum Concurrence et multi-thread
    Réponses: 2
    Dernier message: 12/12/2006, 00h04
  4. Réponses: 6
    Dernier message: 11/05/2006, 16h00
  5. [Debutant] Un thread qui dessine sur une fenetre ???
    Par Spartan03 dans le forum OpenGL
    Réponses: 6
    Dernier message: 05/04/2006, 20h19

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