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 :

Asio : TCP Async_read


Sujet :

Boost C++

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut Asio : TCP Async_read
    Bonjour bonjour, j'ai (encore et toujours) des problèmes avec Asio

    Je m'explique : j'ai lu et me suis inspiré de l'article de Pierre Schwartz (http://khayyam.developpez.com/articl.../architecture/), et je suis en train de réaliser un jeu comportant un serveur, qui ne fait que ça (et non, comme dans l'article, un client qui joue aussi le rôle de serveur), et des clients qui s'y connectent. Autant pour le serveur que pour le client, j'utilise ceci pour mettre en place l'écoute sur le socket TCP, en ayant vérifié que le socket soit bien connecté avant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    m_tcpSocket->async_receive(asio::buffer(m_networkBuffer), boost::bind(&NetworkMachine::tcpAsyncReceive, this, asio::placeholders::error, asio::placeholders::bytes_transferred));
    asio::thread(boost::bind(&asio::io_service::run, &m_io));
    Ensuite, ma fonction tcpAsyncReceive :
    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
     
    void NetworkMachine::tcpAsyncReceive(const asio::error_code& pE, size_t pBytesReceived) {
    	std::cout << "tcpAsyncReceive size : " << m_networkBuffer.size() << std::endl;
    	std::cout << "pE.value() : " << pE.value() << std::endl;
    	if (pE.value() != 0) {
    		EngineEvent e;
    		e.m_type = EngineEvent::REMOVE_MACHINE;
    		e.m_iData["ID"] = m_id;
    		m_parent->pushReceivedEvent(e);
    		return;
    	}
    	// let's deserialize the message
    	if (m_networkBuffer.size() > 0) {
    		std::string strData(&m_networkBuffer[0], m_networkBuffer.size());
    		std::istringstream archiveStream(strData);
    		boost::archive::text_iarchive archive(archiveStream);
     
    		EngineEvent ne;
    		archive >> ne;
     
    		// add the event to the received event queue
    		m_parent->pushReceivedEvent(ne);
    		std::cout << "Something received from " << getNick() << " and added to NetworkEngine received queue." << std::endl;
    	}
    	return;
    }
    J'ai bien d'affiché "tcpAsyncReceive size : 0", 0 erreurs une première fois à l'établissement de la connexion, puis... Plus rien, alors que le client continue d'émettre des données, et que le socket n'est pas fermé (Ce que je sais pour la simple et bonne raison que si je quitte le serveur, le client me dit qu'il est déconnecté, mais pas avant).

    Ma question est donc, ai-je oublié quelque chose ? Faut-il remettre en place l'écoute après que la fonction ait été appellée une fois ?

    Merci.

  2. #2
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Salut,

    A vue de nez je dirais qu'il faut re-demander à recevoir après avoir reçu quelque chose.

    MAT.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    C'est à dire, mettre m_tcpSocket->async_receive(asio::buffer(m_networkBuffer), boost::bind(&NetworkMachine::tcpAsyncReceive, this, asio::placeholders::error, asio::placeholders::bytes_transferred));
    à la fin de tcpAsyncReceive ?

  4. #4
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Ne serait-ce pas approprié d'avoir un thread qui s'occupe de boucler en lisant s'il y a quelque chose à lire, puis qui attend par exemple 50ms avant de retourner voir. Dès qu'il y a quelque chose, il récupère, et il met dans un conteneur de messages, qui sera traité et vidéo au fur et à mesure par le thread principal ?

    Parce que là, ta solution amènerait à un appel récursif dont on ne peut dire s'il termine (si tu modifies encore ta fonction).

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    Citation Envoyé par Alp Voir le message
    Ne serait-ce pas approprié d'avoir un thread qui s'occupe de boucler en lisant s'il y a quelque chose à lire, puis qui attend par exemple 50ms avant de retourner voir. Dès qu'il y a quelque chose, il récupère, et il met dans un conteneur de messages, qui sera traité et vidéo au fur et à mesure par le thread principal ?
    N'est-ce pas ce qui est fait avec m_tcpSocket->async_receive(asio::buffer(m_networkBuffer), boost::bind(&NetworkMachine::tcpAsyncReceive, this, asio::placeholders::error, asio::placeholders::bytes_transferred)); ? (Je ne connais pas encore vraiment Asio, donc j'essaie...)

  6. #6
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Moui.

    Je viens de retrouver cet exemple qui devrait bien t'aider : http://www.boost.org/doc/libs/1_37_0...hat_server.cpp

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    Le problème c'est que je fais quasiment la même chose que sur l'exemple justement, sauf que j'ai tout regroupé en une seule fonction... J'ai essayé de remettre le async_receive à la fin de ma fonction : sur le client ça marche, sans soucis, mais sur le serveur... Elle est bien appelée en boucle dès la première réception :/

  8. #8
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Justement il ne faut pas le faire en une fonction !
    Boost a fait en sorte que tu confies, pour la réception depuis un socket, la gestion d'erreur à une fonction et la gestion de récupération du contenu à une autre. Garde cette séparation et fais vraiment comme ils font eux, ça ira

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    Ok, j'essaie ça et je te dis

    Edit : non, ça boucle toujours... V'la le code :
    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
     
    void NetworkMachine::tcpAsyncReceive(const asio::error_code& pE, size_t pBytesReceived) {
    	std::cout << "tcpAsyncReceive" << std::endl;
    	if (pE.value() != 0) {
    		EngineEvent e;
    		e.m_type = EngineEvent::REMOVE_MACHINE;
    		e.m_iData["ID"] = m_id;
    		m_parent->pushReceivedEvent(e);
    		return;
    	}
    	m_tcpSocket->async_receive(asio::buffer(m_networkBuffer), boost::bind(&NetworkMachine::tcpAsyncReceiveD, this, asio::placeholders::error, asio::placeholders::bytes_transferred));
    }
     
    void NetworkMachine::tcpAsyncReceiveD(const asio::error_code& pE, size_t pBytesReceived) {
    	std::cout << "tcpAsyncReceiveD" << std::endl;
    	if (pE.value() != 0) {
    		return;
    	}
    	// let's deserialize the message
    	if (m_networkBuffer.size() > 0) {
    		std::string strData(&m_networkBuffer[0], m_networkBuffer.size());
    		std::istringstream archiveStream(strData);
    		boost::archive::text_iarchive archive(archiveStream);
     
    		EngineEvent ne;
    		archive >> ne;
     
    		// add the event to the received event queue
    		m_parent->pushReceivedEvent(ne);
    		std::cout << "Something received from " << getNick() << " and added to NetworkEngine received queue." << std::endl;
    	}
    	m_tcpSocket->async_receive(asio::buffer(m_networkBuffer), boost::bind(&NetworkMachine::tcpAsyncReceive, this, asio::placeholders::error, asio::placeholders::bytes_transferred));
    }
    Dès réception du premier paquet, tcpAsyncReceive tcpAsyncReceiveD en continu, je vois pas quoi faire de plus :/

  10. #10
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Pourquoi refais-tu un async_receive dans la deuxième fonction ?
    Il ne faut pas.

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    C'est pourtant ce qui est fait sur l'exemple que tu as linké, si je me trompe pas :
    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
     
      void handle_read_header(const boost::system::error_code& error)
      {
        if (!error && read_msg_.decode_header())
        {
          boost::asio::async_read(socket_,
              boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
              boost::bind(&chat_session::handle_read_body, shared_from_this(),
                boost::asio::placeholders::error));
        }
        else
        {
          room_.leave(shared_from_this());
        }
      }
     
      void handle_read_body(const boost::system::error_code& error)
      {
        if (!error)
        {
          room_.deliver(read_msg_);
          boost::asio::async_read(socket_,
              boost::asio::buffer(read_msg_.data(), chat_message::header_length),
              boost::bind(&chat_session::handle_read_header, shared_from_this(),
                boost::asio::placeholders::error));
        }
        else
        {
          room_.leave(shared_from_this());
        }
      }
    Et, si je ne le mets pas sur la deuxième, toutes les données reçues iront sur la deuxième, non ?

  12. #12
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Peut-être qu'il faut utiliser async_read, genre comme dans l'exemple, plutôt que d'aller taper directement dans le async_receive de la socket ?
    En tous cas c'est comme ça que je procède systématiquement pour du TCP.

    MAT.

  13. #13
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    En utilisant ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    asio::async_read(m_tcpSocket,
    asio::buffer(m_networkBuffer),
    boost::bind(&NetworkMachine::tcpAsyncReceive, this,
    asio::placeholders::error,
    asio::placeholders::bytes_transferred));
    Je me retrouve avec des erreurs de compilations plutôt obscures...
    Citation Envoyé par G++
    /usr/include/asio/impl/read.ipp: In function ‘void asio::async_read(AsyncReadStream&, const MutableBufferSequence&, CompletionCondition, ReadHandler) [with AsyncReadStream = asio::basic_stream_socket<asio::ip::tcp, asio::stream_socket_service<asio::ip::tcp> >*, MutableBufferSequence = asio::mutable_buffers_1, CompletionCondition = asio::detail::transfer_all_t, ReadHandler = boost::_bi::bind_t<void, boost::_mfi::mf2<void, NetworkMachine, const asio::error_code&, long unsigned int>, boost::_bi::list3<boost::_bi::value<NetworkMachine*>, boost::arg<1> (*)(), boost::arg<2> (*)()> >]’:
    /usr/include/asio/impl/read.ipp:211: instantiated from ‘void asio::async_read(AsyncReadStream&, const MutableBufferSequence&, ReadHandler) [with AsyncReadStream = asio::basic_stream_socket<asio::ip::tcp, asio::stream_socket_service<asio::ip::tcp> >*, MutableBufferSequence = asio::mutable_buffers_1, ReadHandler = boost::_bi::bind_t<void, boost::_mfi::mf2<void, NetworkMachine, const asio::error_code&, long unsigned int>, boost::_bi::list3<boost::_bi::value<NetworkMachine*>, boost::arg<1> (*)(), boost::arg<2> (*)()> >]’
    network_machine.cpp:41: instantiated from here
    /usr/include/asio/impl/read.ipp:200: erreur: request for member ‘async_read_some’ in ‘s’, which is of non-class type ‘asio::basic_stream_socket<asio::ip::tcp, asio::stream_socket_service<asio::ip::tcp> >*’

  14. #14
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Tu utilises quelle version de boost ?
    Pourquoi c'est asio:: et non boost::asio:: tiens d'ailleurs ?

    MAT.

  15. #15
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    J'ai Boost 1.35, et je pense que je viens de trouver la cause de pas mal de soucis... J'ai aussi Asio 1.1.0, alors qu'Asio fait maintenant partie de Boost, je devrais pas en avoir besoin je me trompe ?

  16. #16
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Asio fait partie de boost depuis justement la version 1.35 donc oui en effet tu devrais utiliser boost/asio et boost::asio plutôt.

    MAT.

  17. #17
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Au passage, récupère la 1.37. Parce que par exemple je me suis basé sur sa doc pour les exemples donnés etc.

  18. #18
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    En effet, j'ai de jolis conflits entre Asio et Boost::asio en fait... Je fais du ménage, et je vous donne des nouvelles ^^

  19. #19
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    Voilà, j'ai donc viré Asio, et mit Boost en 1.37. Je compile avec ma ligne d'avant, les deux fonctions sont appelées en boucle.
    J'essaie donc avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    boost::asio::async_read(m_tcpSocket,
           boost::asio::buffer(m_networkBuffer),
           boost::bind(&NetworkMachine::tcpAsyncReceive, this,
           boost::asio::placeholders::error,
           boost::asio::placeholders::bytes_transferred));
    et GCC me répond toujours de manière barbare... :

    Citation Envoyé par GCC
    /usr/include/boost/asio/impl/read.ipp: In function ‘void boost::asio::async_read(AsyncReadStream&, const MutableBufferSequence&, CompletionCondition, ReadHandler) [with AsyncReadStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, MutableBufferSequence = boost::asio::mutable_buffers_1, CompletionCondition = boost::asio::detail::transfer_all_t, ReadHandler = boost::_bi::bind_t<void, boost::_mfi::mf2<void, NetworkMachine, const boost::system::error_code&, long unsigned int>, boost::_bi::list3<boost::_bi::value<NetworkMachine*>, boost::arg<1> (*)(), boost::arg<2> (*)()> >]’:
    /usr/include/boost/asio/impl/read.ipp:232: instantiated from ‘void boost::asio::async_read(AsyncReadStream&, const MutableBufferSequence&, ReadHandler) [with AsyncReadStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, MutableBufferSequence = boost::asio::mutable_buffers_1, ReadHandler = boost::_bi::bind_t<void, boost::_mfi::mf2<void, NetworkMachine, const boost::system::error_code&, long unsigned int>, boost::_bi::list3<boost::_bi::value<NetworkMachine*>, boost::arg<1> (*)(), boost::arg<2> (*)()> >]’
    network_machine.cpp:75: instantiated from here
    /usr/include/boost/asio/impl/read.ipp:216: erreur: request for member ‘get_io_service’ in ‘s’, which is of non-class type ‘boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*’
    /usr/include/boost/asio/impl/read.ipp:232: instantiated from ‘void boost::asio::async_read(AsyncReadStream&, const MutableBufferSequence&, ReadHandler) [with AsyncReadStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, MutableBufferSequence = boost::asio::mutable_buffers_1, ReadHandler = boost::_bi::bind_t<void, boost::_mfi::mf2<void, NetworkMachine, const boost::system::error_code&, long unsigned int>, boost::_bi::list3<boost::_bi::value<NetworkMachine*>, boost::arg<1> (*)(), boost::arg<2> (*)()> >]’
    network_machine.cpp:75: instantiated from here
    /usr/include/boost/asio/impl/read.ipp:221: erreur: request for member ‘async_read_some’ in ‘s’, which is of non-class type ‘boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*’
    make: *** [network_machine.o] Erreur 1

  20. #20
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 132
    Par défaut
    Au temps pour moi, j'avais pas remarqué la p'tite étoile... J'ai donc ça maintenant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    boost::asio::async_read((*m_tcpSocket),
         boost::asio::buffer(m_networkBuffer),
         boost::bind(&NetworkMachine::tcpAsyncReceive, this,
         boost::asio::placeholders::error,
         boost::asio::placeholders::bytes_transferred));
    Qui se compile, s'exécute... Et boucle toujours :/

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [ASIO] tcp::iostream et HTTPS
    Par mitkl dans le forum Boost
    Réponses: 2
    Dernier message: 06/06/2012, 18h57
  2. boost::asio::ip::tcp::socket est elle thread safe ?
    Par nemodev dans le forum Boost
    Réponses: 4
    Dernier message: 24/02/2010, 13h08
  3. Réponses: 11
    Dernier message: 24/09/2008, 14h22
  4. Différence entre TCP, UDP, ICMP
    Par GliGli dans le forum Développement
    Réponses: 1
    Dernier message: 13/09/2002, 08h25
  5. transfert d'un fichier bitmap en socket tcp
    Par localhost dans le forum C++Builder
    Réponses: 5
    Dernier message: 29/07/2002, 00h40

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