1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    juillet 2017
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : juillet 2017
    Messages : 11
    Points : 3
    Points
    3

    Par défaut Fonction accept() bloquante avec winsock2

    Bonjour,

    J'ai suivis le cours de Bousk sur winsock, et celui-ci m'as beaucoup plu.
    Cependant, j'ai un soucis dans un programme et j'aurais aimé savoir si quelqu'un avait une solution à me proposer :

    dans mon application serveur, j'utilise un thread qui accepte les clients en continue pour ne pas bloquer l'application. Malheureusement lorsque je souhaite éteindre l'application et que du coup j'appelle thread.join() pour attendre la fin du thread, l'application reste bloqué car le thread ne se termine pas car il est bloqué sur la fonction accept() jusq'à ce qu'un client tente de se connecter au serveur.

    Quelqu'un connait-il une solution pour rendre la fonction accept() non bloquante, avec un timeout par exemple?

    Merci,

    Louis

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    septembre 2005
    Messages
    26 477
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : septembre 2005
    Messages : 26 477
    Points : 38 213
    Points
    38 213

    Par défaut

    Tu peux utiliser select(), et ne faire le accept() que si select() retourne l'info comme quoi il y a un client à accepter.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Rédacteur/Modérateur

    Homme Profil pro
    Network game programmer
    Inscrit en
    juin 2010
    Messages
    4 560
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 4 560
    Points : 18 255
    Points
    18 255

    Par défaut

    Salut,

    la mise en place du mode non bloquant est identique chez le client et le serveur.
    Tu peux
    - utiliser select pour vérifier que le socket est prêt en lecture;
    - préférer poll toujours pour vérifier l'état de la lecture;
    - mettre en place le vrai mode non bloquant avec des sockets non bloquants.
    Si tu utilises un socket non bloquant, accept retournera directement INVALID_SOCKET s'il n'y a aucun client à accepter. http://bousk.developpez.com/cours/re...veur/#LIII-D-3
    Toutes ces techniques sont dans le même article Envoi et réception depuis le serveur.

    Sinon, tu peux aussi simplement fermer le socket avant d'appeler join. Ca devrait débloquer accept qui retournera alors INVALID_SOCKET.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    juillet 2017
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : juillet 2017
    Messages : 11
    Points : 3
    Points
    3

    Par défaut

    Super, merci pour vos réponse!
    Je vais essayer tout de suite.

  5. #5
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    juillet 2017
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : juillet 2017
    Messages : 11
    Points : 3
    Points
    3

    Par défaut

    Ça fonctionne bien en fermant le socket, merci.

    Je me pencherait sur le select plus tard car il m'as l'air bien plus complexe, j'ai eu du mal à comprendre lors de m'a première lecture.

  6. #6
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    juillet 2017
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : juillet 2017
    Messages : 11
    Points : 3
    Points
    3

    Par défaut

    Par contre savez-vous pourquoi mon thread est non joignable?
    J'obtiens une exception quand j'appelle join() qui 'm’indique que le thread n'est pas joignable.

  7. #7
    Rédacteur/Modérateur

    Homme Profil pro
    Network game programmer
    Inscrit en
    juin 2010
    Messages
    4 560
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 4 560
    Points : 18 255
    Points
    18 255

    Par défaut

    Pour ça il faudrait savoir ce que tu fais avec ton thread.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  8. #8
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    juillet 2017
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : juillet 2017
    Messages : 11
    Points : 3
    Points
    3

    Par défaut

    Je créer un objet Serveur. Quand j'appelle sa méthode AcceptClients(), la méthode lance le thread qui se met alors à accepter des clients et à en stocker les sockets dans un vector en y ayant accès par référence, et tout ça en continue via une boucle while(bool).
    Lorsque j'appelle la méthode Stop() du serveur, celui-ci change la valeur du booléen, ferme le socket puis appelle la méthode join() du thread

    Et c'est à l'appel de join() que le programme plante et me sort cette erreur :

    terminate called after throwing an instance of 'std::system_error'
    what(): Invalid argument

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    septembre 2005
    Messages
    26 477
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : septembre 2005
    Messages : 26 477
    Points : 38 213
    Points
    38 213

    Par défaut

    Fais gaffe, while(bool) n'est pas garanti marcher. S'il est déclaré volatile en plus, c'est garanti sur certaines plate-formes (dont Windows).

    Aussi, peut-on voir le code qui lance le thread et le code qui appelle join()?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Rédacteur/Modérateur

    Homme Profil pro
    Network game programmer
    Inscrit en
    juin 2010
    Messages
    4 560
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 4 560
    Points : 18 255
    Points
    18 255

    Par défaut

    T'es sûr que t'as pas déjà détaché ou join le thread ?
    Ce que tu décris est exactement ce que je fais dans chacun de mes programmes et fonctionne parfaitement.

    Y'a pas 500 façons d'avoir cette exception, ton thread n'est pas joignable.
    http://www.cplusplus.com/reference/t...read/joinable/
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  11. #11
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    juillet 2017
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : juillet 2017
    Messages : 11
    Points : 3
    Points
    3

    Par défaut

    La fonction AcceptClients(), que j'appelle au début de mon programme :
    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
     
    void Server::AcceptClients(std::vector<Client> &clients)
    {
        m_isClientsAccepted = true;
        SOCKET *socket = &m_socket;
        bool *isClientsAccepted = &m_isClientsAccepted;
        m_threadAccept = std::thread([isClientsAccepted, socket, &clients]()
        {
            while(isClientsAccepted)
            {
                sockaddr_in from = { 0 };
                int addrlen = sizeof(from);
                SOCKET newClient = accept(*socket, (SOCKADDR*)(&from), &addrlen);
     
                if (newClient != INVALID_SOCKET)
                {
                    clients.push_back(Client(newClient, Sockets::GetAddress(from), ntohs(from.sin_port)));
                }
                /*else
                {
                    break;
                }*/
            }
        });
    }
    Pour information la classe Client contient juste un socket, une ip, et un port. Elle sert à stocker ces informations de manière simple dans un vector.


    Et la fonction Stop(), que j'appelle à la fin de mon programme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    bool Server::Stop()
    {
        m_isClientsAccepted = false;
        bool ret = Sockets::CloseSocket(m_socket);
        m_threadAccept.join();
        return ret;
    }
    Alors je ne sait pas si c'est une bonne idée d'avoir fait passer mes variable de la classe Server par des pointeurs(m_socket, et m_isClientsAccepted), mais sinon le compilateur me retournée une erreur que je ne comprenais pas avec lambda ou je ne sais quoi...

  12. #12
    Rédacteur/Modérateur

    Homme Profil pro
    Network game programmer
    Inscrit en
    juin 2010
    Messages
    4 560
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 4 560
    Points : 18 255
    Points
    18 255

    Par défaut

    Le passage par copie de pointeur est pas terrible en effet, tu pourrais simplement passer this. Ta variable m_isClientsAccepted est assez trompeuse aussi mais rien de dramatique.
    Es-tu sur de ne pas simplement appeler Close plusieurs fois ? Ou sans appeler AcceptClients au préalable et donc tu as un std::thread default-constructed qui n'est pas joinable.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  13. #13
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    juillet 2017
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : juillet 2017
    Messages : 11
    Points : 3
    Points
    3

    Par défaut

    Citation Envoyé par Bousk Voir le message
    Es-tu sur de ne pas simplement appeler Close plusieurs fois ?
    Oh mon dieu! je crois bien que si... Je me sent bien bête tout d'un coup.
    J'ai effectivement fais un appel à Stop() dans le destructeur de mon objet Server...

    Merci beaucoup

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

Discussions similaires

  1. Problème avec les sockets et la fonction accept
    Par projeticq dans le forum Réseau
    Réponses: 6
    Dernier message: 13/04/2007, 11h37
  2. [swing][socket]méthode ServerSocket.accept() bloquante?
    Par the_ugly dans le forum EDT/SwingWorker
    Réponses: 6
    Dernier message: 07/11/2005, 11h15
  3. Réponses: 5
    Dernier message: 02/09/2005, 12h47
  4. Réponses: 5
    Dernier message: 12/01/2005, 20h58
  5. Gestion de sockets: fonction Accept
    Par keupon dans le forum MFC
    Réponses: 12
    Dernier message: 22/01/2004, 18h48

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