Précédent   Forum du club des développeurs et IT Pro > C et C++ > C++ > Bibliothèques > Boost
Boost Forum d'entraide C++ sur Boost
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 16/02/2013, 16h54   #1
SalutAVous
Membre à l'essai
 
Homme
Étudiant
Inscription : décembre 2011
Messages : 35
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 : 35
Points : 21
Points : 21
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 :
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 !
SalutAVous est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2013, 19h23   #2
Arzar
Membre Expert
 
Inscription : mai 2008
Messages : 937
Détails du profil
Informations forums :
Inscription : mai 2008
Messages : 937
Points : 1 785
Points : 1 785
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 :
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 :
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 :
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.
Arzar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2013, 23h41   #3
SalutAVous
Membre à l'essai
 
Homme
Étudiant
Inscription : décembre 2011
Messages : 35
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 : 35
Points : 21
Points : 21
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 :
1
2
3
 
Handler& callback = boost::get<0>(handler);
callback(e);
Super, je comprends maintenant

Citation:
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 :
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 :
Citation:
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.
SalutAVous est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 23h11.


 
 
 
 
Partenaires

Hébergement Web