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

Boost C++ Discussion :

[Boost Asio] Utilisation des tuples et organisation des classes


Sujet :

Boost C++

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2011
    Messages : 51
    Points : 59
    Points
    59
    Par défaut [Boost Asio] Utilisation des tuples et organisation des classes
    Bonjour,

    Je lis le tutoriel suivant sur Boost Asio : http://gwenael-dunand.developpez.com...pp/boost/asio/ et j'essaye de comprendre le fonctionnement du serveur dans la partie 7.

    J'ai en fait deux questions.

    La première concerne l'utilisation des tuples. Dans les méthodes handle_read_header et handle_read_data de la classe tcp_connection on utilise l'instruction suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::get<0>(handler)(e);
    J'ai compris l'intérêt d'utiliser les tuples, je sais que boost::get<0>(handler) nous permet d'accéder à l'élément 0 du tuple handler, mais pourquoi rajouter ce (e) à la suite ? Je ne trouve rien dans la doc de Boost Tuple.


    La deuxième question est plus générale. Je vois qu'il y a beaucoup de classes à créer pour la création du serveur et je voudrais savoir si cette manière d'organiser nos classes varie beaucoup selon les projets ?
    Si je crée une application réseau est ce que je pourrais me baser sur cette "organisation des classes" même s'il ne s'agit pas d'un chat ? Est ce que je pourrais chercher à obtenir une organisation similaire (plus ou moins bien sûr) ?

    J'attends vos réponses et conseils avec impatience

    Bonne journée !

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonjour,
    Citation Envoyé par SalutAVous Voir le message
    La première concerne l'utilisation des tuples. Dans les méthodes handle_read_header et handle_read_data de la classe tcp_connection on utilise l'instruction suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::get<0>(handler)(e);
    [...] mais pourquoi rajouter ce (e) à la suite ?
    Ce qui a été mis dans le tuple comme premier élément est une callback prenant en argument un system::error_code.
    Donc ce que fait ce bout de code c'est extraire la callback du tuple et l’appeler aussitôt en passant e comme argument.
    (Par callback j'entends un objet appelable avec l’opérateur() comme un pointeur de fonction ou une fonction-objet)
    On aurait pu faire en deux temps :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Handler& callback = boost::get<0>(handler);
    callback(e);
    Citation Envoyé par SalutAVous Voir le message
    J'ai compris l'intérêt d'utiliser les tuples
    Vraiment ? Car moi je ne comprends pas bien pourquoi l'auteur du tutoriel les a utilisé.
    Quel est l'intérêt de passer en argument des tuple d'un seul élément ? Pourquoi ne pas passer directement l'élément en question ?
    Il me semble qu'on pourrait utiliser directement un code comme celui-ci :
    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
     
       // Lecture asynchrone de données depuis le socket
       template <typename T, typename Handler>
       void async_read(T& t, Handler handler)
       {
       boost::asio::async_read(m_socket, boost::asio::buffer(m_inbound_header),
          boost::bind(&tcp_connection::handle_read_header<T, Handler>,
                          this, boost::asio::placeholders::error, boost::ref(t), handler));
       }	
     
       //Interprétation du header
       template <typename T, typename Handler>
       void handle_read_header(const boost::system::error_code& e, T& t, Handler handler)
       {
          if (e)
          {
             handler(e);
          }
          else
          {
             // Détermine la longueur du vrai message (11)
             std::istringstream is(std::string(m_inbound_header, header_length));
    	std::size_t m_inbound_datasize = 0;
    	if (!(is >> std::hex >> m_inbound_datasize))
    	{
    	   // Header non valide, on informe la fonction appelante
    	   boost::system::error_code error(boost::asio::error::invalid_argument);
               handler(error);
    	   return;
    	}
     
    	// On récupère les données (12)
    	m_inbound_data.resize(m_inbound_datasize);
     
    	boost::asio::async_read(m_socket, boost::asio::buffer(m_inbound_data),
               boost::bind(&tcp_connection::handle_read_data<T, Handler>, this,
    				boost::asio::placeholders::error, boost::ref(t), handler));
    	}
       }
     
       // Les données reçues, on les désérialise (13)
       template <typename T, typename Handler>
       void handle_read_data(const boost::system::error_code& e,
       T& t, Handler handler)
       {
          if (e)
          {
             handler(e);
          }
          else
          {
             // On extrait (14)
             try
    	 {
    	    std::string archive_data(&m_inbound_data[0], m_inbound_data.size());
    	    std::istringstream archive_stream(archive_data);
    	   boost::archive::text_iarchive archive(archive_stream);
    	   archive >> t;
    	  }
    	  catch (std::exception&)
    	  {
    	      // En cas d'échec
    	      boost::system::error_code error(boost::asio::error::invalid_argument);
    	     handler(error);
    	     return;
    	   }
     
    	// On informe l'appelant que tout s'est bien passé. (15)
    	handler(e);
    	}
       }
    Citation Envoyé par SalutAVous Voir le message
    La deuxième question est plus générale. Je vois qu'il y a beaucoup de classes à créer pour la création du serveur et je voudrais savoir si cette manière d'organiser nos classes varie beaucoup selon les projets ?
    Si je crée une application réseau est ce que je pourrais me baser sur cette "organisation des classes" même s'il ne s'agit pas d'un chat ? Est ce que je pourrais chercher à obtenir une organisation similaire (plus ou moins bien sûr) ?
    Là je ne sais pas trop, pas assez d'expérience sur les serveurs, faut voir ce qu'en pense les autres intervenants.

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2011
    Messages : 51
    Points : 59
    Points
    59
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Bonjour,


    Ce qui a été mis dans le tuple comme premier élément est une callback prenant en argument un system::error_code.
    Donc ce que fait ce bout de code c'est extraire la callback du tuple et l’appeler aussitôt en passant e comme argument.
    (Par callback j'entends un objet appelable avec l’opérateur() comme un pointeur de fonction ou une fonction-objet)
    On aurait pu faire en deux temps :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Handler& callback = boost::get<0>(handler);
    callback(e);
    Super, je comprends maintenant

    Vraiment ? Car moi je ne comprends pas bien pourquoi l'auteur du tutoriel les a utilisé.
    Quel est l'intérêt de passer en argument des tuple d'un seul élément ? Pourquoi ne pas passer directement l'élément en question ?
    Il me semble qu'on pourrait utiliser directement un code comme celui-ci :
    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
     
       // Lecture asynchrone de données depuis le socket
       template <typename T, typename Handler>
       void async_read(T& t, Handler handler)
       {
       boost::asio::async_read(m_socket, boost::asio::buffer(m_inbound_header),
          boost::bind(&tcp_connection::handle_read_header<T, Handler>,
                          this, boost::asio::placeholders::error, boost::ref(t), handler));
       }	
     
       //Interprétation du header
       template <typename T, typename Handler>
       void handle_read_header(const boost::system::error_code& e, T& t, Handler handler)
       {
          if (e)
          {
             handler(e);
          }
          else
          {
             // Détermine la longueur du vrai message (11)
             std::istringstream is(std::string(m_inbound_header, header_length));
    	std::size_t m_inbound_datasize = 0;
    	if (!(is >> std::hex >> m_inbound_datasize))
    	{
    	   // Header non valide, on informe la fonction appelante
    	   boost::system::error_code error(boost::asio::error::invalid_argument);
               handler(error);
    	   return;
    	}
     
    	// On récupère les données (12)
    	m_inbound_data.resize(m_inbound_datasize);
     
    	boost::asio::async_read(m_socket, boost::asio::buffer(m_inbound_data),
               boost::bind(&tcp_connection::handle_read_data<T, Handler>, this,
    				boost::asio::placeholders::error, boost::ref(t), handler));
    	}
       }
     
       // Les données reçues, on les désérialise (13)
       template <typename T, typename Handler>
       void handle_read_data(const boost::system::error_code& e,
       T& t, Handler handler)
       {
          if (e)
          {
             handler(e);
          }
          else
          {
             // On extrait (14)
             try
    	 {
    	    std::string archive_data(&m_inbound_data[0], m_inbound_data.size());
    	    std::istringstream archive_stream(archive_data);
    	   boost::archive::text_iarchive archive(archive_stream);
    	   archive >> t;
    	  }
    	  catch (std::exception&)
    	  {
    	      // En cas d'échec
    	      boost::system::error_code error(boost::asio::error::invalid_argument);
    	     handler(error);
    	     return;
    	   }
     
    	// On informe l'appelant que tout s'est bien passé. (15)
    	handler(e);
    	}
       }
    D'après ce que j'ai compris (mais peut être que je n'ai pas compris aussi) la fonction boost::bind() ne peut pas utiliser une fonction qui a été passée en paramètre à une fonction template dans laquelle elle est utilisée.

    Or le handler est passé en paramètre à la fonction template handle_read_header. Et dans cette fonction template handle_read_header on utilise la fonction boost::bind(), qui ne peut donc pas utiliser la fonction handler qui a été passée en paramètre à handle_read_header.

    Dans le tuto il est dit :
    Le code est relativement long, surtout à cause du fait que boost::bind ne supporte pas l'appel récursif lorsqu'il est templaté. C'est-à-dire que boost::bind ne peut pas (pour l'instant sans doute) binder une fonction passée via un template où boost::bind est utilisé.
    Du coup, on est obligé de passer par des tuple, qui n'ont normalement rien à voir là dedans. Je les ai gardés pour avoir un code qui compile. Faites en abstraction et gardez à l'esprit que le tuple en question est juste le callback.
    Après je n'ai pas cherché à vérifier si cela marchait sans utiliser de tuples, et peut être que j'ai simplement mal compris l'intérêt d'utiliser les tuples.



    En tout cas merci pour cette réponse, et j'en attends d'autres, concernant ma deuxième question.

Discussions similaires

  1. Réponses: 1
    Dernier message: 28/06/2012, 16h04
  2. Réponses: 1
    Dernier message: 27/04/2012, 16h41
  3. boost::spirit utilisation des arguments
    Par SKone dans le forum Boost
    Réponses: 11
    Dernier message: 28/01/2011, 11h16
  4. Réponses: 6
    Dernier message: 05/05/2010, 15h21
  5. [OL-2003] Gestion des règles d'organisation des dossiers
    Par leking41 dans le forum VBA Outlook
    Réponses: 0
    Dernier message: 02/03/2010, 07h58

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