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

Threads & Processus C++ Discussion :

Boost : thread et sockets


Sujet :

Threads & Processus C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2010
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Août 2010
    Messages : 86
    Par défaut Boost : thread et sockets
    Bonjour,
    Je bosse actuellement sur un petit projet.
    Je dois faire un petit serveur qui écoute sur le port 18000.
    Lorsqu'un client se connecte et envoi ça chaine de caractère, en fonction du deuxième caractère, le serveur lance un thread spécifique, effectue le traitement et renvoie le resulat par la socket du client.
    Exemple : le serveur recoit le caractere 'i' : il lance un thread, effectu le traitement (ici mathématique) et renvoit le résultat dans la socket du client

    Mon problème c'est de pourvoir transférer proprement la socket à un thread et de pourvoir renvoyer les résultat par cette socket.

    Le thread créé lance un foncteur.

    Voici mon code

    main.cpp
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string>
    #include <cstring>
    #include <unistd.h>
    #include <boost/asio.hpp>
    #include <boost/thread/thread.hpp>
    #include <iostream>
    #include "calculFrey.h"
     
    using boost::asio::ip::tcp;
    using namespace boost;
    using namespace std;
     
    int main(int argc, char* argv[])
    {
        //On déclare une socket serveur et on écoute
        try
        {
            //Création de la socket et écooute
            boost::asio::io_service io_service;
            tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 18000));
     
            cout<<"Programme prêt."<<endl;
            cout<<"Attente des requêtes..."<<endl;
     
            //On attends les connections
            for(;;)
            {
                //Attente des connections
                tcp::socket socket(io_service);
                acceptor.accept(socket);
     
     
                //Réception de la requête
                boost::array<char, 128> buf;
                boost::system::error_code error;
                socket.read_some(boost::asio::buffer(buf), error);
                string req=buf.data();
     
                if(req.at(1)=='i')
                {
                    calculFrey frey(&socket); //Instanciation du fonctor avec l'adresse de la socket client
                    thread t(frey); //Lancement du fonctor dans le thread
                }
            }
     
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
        }
    }
    calculFrey
    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
    #ifndef CALCULFREY_H
     
    #define CALCULFREY_H
     
     
    #include <boost/asio.hpp>
    #include <boost/thread/thread.hpp>
    #include <iostream>
    using boost::asio::ip::tcp;
    using namespace boost;
    using namespace std;
     
    /**Classe functor permettant de lancer un calcul pour Frey*/
     
     
     
    class calculFrey
     
    {
        private:
        tcp::socket* sock;
     
     
        public:
            calculFrey(tcp::socket* sock)
            {
                this->sock=sock;
                cout<<"Adresse de la socket dans le foncteur"<<sock<<endl;
            }
            /**Surcharge de l'opérateur ()  pour faire le functor*/
            void operator()(void)
            {
                cout<<"Passage dans le functore pour Frey"<<endl;
                boost::asio::write(*this->sock, boost::asio::buffer("hello !"));
            }
     
    };
     
     
     
    #endif // CALCULFREY_H

    J'ai une solution qui n'en n'est pas vraiment une car la socket se ferme avant que le thread ne puisse écrire dedans.

    Le problème c'est que la connection se ferme dès que le serveur à recu la chaine de caractères le code suivant me lève une exception expliquant que j'utilise un mauvais descripteur de socket :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::asio::write(*this->sock, boost::asio::buffer("hello !"));
    Donc j'ai plusieurs questions :
    -Comment passer à un foncteur des arguments ?
    -Comment faire pour pouvoir envoyer une socket dans le thread et écrire dessus ?
    -L'architecture du programme est-elle mauvaise ?

    Merci d'avoir prit le temps d'arriver au bout.

  2. #2
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Pourquoi passer par un pointeur ?

    La réponse a ta question est : lorsque tu atteins la fin du for (juste après le if), la socket est détruite, et une autre est construite à la place. Du coup, puisque ton code est exécuté de manière asynchrone, tu pointes sur un destructeur invalide.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  3. #3
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2010
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Août 2010
    Messages : 86
    Par défaut
    Oui j'ai bien compris que je pointais sur un truc qui existe plus.
    Mais comment régler ce problème ?

    Je le fais avec un pointeur parce-qu'en passage par valeur le compilo gueule.

    Merci.

  4. #4
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    C'est une très bonne question. Puisque Boost.asio n'accepte pas de copie ses sockets (et je me demande bien pourquoi ; si ce n'est un design un peu étrange qui considère qu'une socket UDP et une socket TCP, c'est la même chose à la base), il faut aller au delà.

    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
    class calculFrey
    {
    private:
        tcp::socket sock;
     
     
    public:
            calculFrey(boost::asio::io_service& service, tcp::socket::native_type sockfd)
            : sock(service, tcp().protocol(), sockfd)
            { }
    
            /**Surcharge de l'opérateur ()  pour faire le functor*/
            void operator()()
            {
                cout<<"Passage dans le functore pour Frey"<<endl;
                boost::asio::write(sock, boost::asio::buffer("hello !"));
            }
     };
    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
     
    #include <boost/thread/thread.hpp>
    #include <iostream>
    #include "calculFrey.h"
     
    using boost::asio::ip::tcp;
    using namespace boost;
    using namespace std;
     
    int main(int argc, char* argv[])
    {
        //On déclare une socket serveur et on écoute
        try
        {
            //Création de la socket et écooute
            boost::asio::io_service io_service;
            tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 18000));
     
            cout<<"Programme prêt."<<endl;
            cout<<"Attente des requêtes..."<<endl;
     
            //On attends les connections
            for(;;)
            {
                //Attente des connections
                tcp::socket socket(io_service);
                acceptor.accept(socket);
     
     
                //Réception de la requête
                boost::array<char, 128> buf;
                boost::system::error_code error;
                socket.read_some(boost::asio::buffer(buf), error);
                string req=buf.data();
     
                if(req.at(1)=='i')
                {
                    //Lancement du fonctor dans le thread
                    thread t(calculFrey(io_service, socket.native()); 
                    // la socket est vidée de son contenu, de la manière la 
                    // plus trash possible
                    socket.assign(tcp().protocol(), 0);
                }
            }
         }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
        }
    }
    Si quelqu'un d'autre voit une autre solution, je suis preneur aussi. A lire la doc, je ne vois pas mieux, et je ne sais même pas si ça passera (le assign() pourrait être un poil violent et fermer la socket avant de faire le assign(), auquel cas, il faut complètement repenser le design).

    On notera quand même que cette architecture est très commune, et pourtant, si j'ai bien tout lu la doc de boost::asio, impossible à mettre en place proprement avec cette librairie (il faudrait un move constructor à la classe tcp::socket, ou un équivalent). C'est assez décevant, vu le potentiel de cette librairie.

    (note: une autre solution existe, à base de bost::shared_ptr. Mais je n'aime pas les pointeurs intelligents).
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  5. #5
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2010
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Août 2010
    Messages : 86
    Par défaut
    Ha enfin quelqu'un qui me comprends :-)
    Je test ça demain et je vous tient au courant.
    Merci beaucoup !

  6. #6
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    (note: une autre solution existe, à base de bost::shared_ptr. Mais je n'aime pas les pointeurs intelligents).

    Je sais que c'est hors topic, mais je serai curieux d'avoir ton avis dessus... Perso je trouve ça hyper pratique, et tout mon code est infesté de scoped_ptr et shared_ptr....

  7. #7
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par poukill Voir le message

    Je sais que c'est hors topic, mais je serai curieux d'avoir ton avis dessus... Perso je trouve ça hyper pratique, et tout mon code est infesté de scoped_ptr et shared_ptr....
    scoped_ptr<> a un intérêt (tout comme auto_ptr, mais en mieux). shared_ptr<> est utilisé pour ne pas avoir à gérer la propriété des objets (qui appartient à quoi). Hors, sans notion de propriété, il n'y a pas de notion de durée de vie (d'où l'utilisation d'un pointeur qui se détruit tout seul, comme un grand, quand personne ne l'utilise plus). Ca veut dire en gros que tu ne contrôle rien, que le plus petit changement dans ton code peut avoir des conséquence que tu ne peux pas prévoir, etc. C'est une horreur en maintenance, mais aussi en architecture - car réaliser une architecture, c'est mettre en évidence les liens qui existent entre les différents concepts (classes) de l'application, y compris les liens de propriété. shared_ptr<> ne met en évidence aucun lien, voire les cache, ce qui participe à rendre bancal une architecture.

    C'est pratique, oui, comme goto l'est. Après avoir tapé sur les tête des singletons pendant des années, voici maintenant venir le temps des pointeurs intelligents qui font des choses inintelligibles
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

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

Discussions similaires

  1. Boost : threads et sockets
    Par Elenaher dans le forum Bibliothèques
    Réponses: 1
    Dernier message: 28/12/2008, 13h24
  2. [Débutant] boost::thread non-lvalue
    Par Tymk dans le forum Boost
    Réponses: 16
    Dernier message: 18/11/2006, 14h23
  3. Questions de perfomance avec boost::thread
    Par Rafy dans le forum Boost
    Réponses: 36
    Dernier message: 05/10/2006, 15h21
  4. boost::thread et OpenGL
    Par Kurisu dans le forum Boost
    Réponses: 12
    Dernier message: 19/09/2006, 13h23

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