2016-07-26 37 views
1

Ich habe vor kurzem ein Problem mit boost :: asio asynchronen Aufgaben festgestellt. Ich möchte einen Zeiger auf ein Objekt zurückgeben, das auf einen Port hört. Es funktioniert, wenn ich die Methode socket.read_some verwende, aber diese Methode blockiert mein Haupt und ich möchte meine MyClass :: create-Methode zurückgeben.Boost Asio - Warum starten meine asynchronen Operationen nicht?

Also versuchte ich einen async_read-Aufruf, aber ich sah, dass innerhalb meiner read() -Methode keine asynchronen Aufgaben gestartet werden. Ich habe versucht, herauszufinden, was das Problem verursachen könnte, aber ich sehe keine Lösung für dieses Problem.

Hier ist mein Code, hier ist es nicht mit einem async_read aber mit einem async_wait, und das gleiche Problem erscheint, wird der Timer nicht gestartet.

Danke für jede Hilfe, die ich bekommen könnte.

Die Header-Datei:

#ifndef MYCLASS_HPP 
#define MYCLASS_HPP 

#include <memory> 
#include <boost/asio.hpp> 

class MyClass 
{ 
public: 
MyClass(boost::asio::io_service& ios); 

void read(); 
void read_handler(const boost::system::error_code& error); 

static std::shared_ptr<MyClass> create(std:: string const & host, uint16_t port); 

bool connect (std::string const & host, uint16_t port); 
void connect_handler(const boost::system::error_code& error); 


boost::asio::ip::tcp::socket m_socket; 
bool    m_flag; 
std::vector<uint8_t>  m_buffer; 
}; 

#endif 

Quelldatei:

#include "MyClass.hpp" 

#include <boost/bind.hpp> 

MyClass::MyClass(boost::asio::io_service& ios) 
    :m_flag(false), m_socket(ios), m_buffer(20) 
{ 
} 

void MyClass::read_handler(const boost::system::error_code& er) 
{ 
    std::cout << "Timer waited 5 sec" << std::endl; 
} 


void MyClass::read() 
{ 
    boost::asio::deadline_timer t(m_socket.get_io_service(),boost::posix_time::seconds(5)); 
    t.async_wait(boost::bind(&MyClass::read_handler,this,boost::asio::placeholders::error)); 
    m_socket.get_io_service().run();//Should make the io_service wait for all asynchronous tasks to finish 
    std::cout << "This message should be displayed after the wait" << std::endl; 
} 

void MyClass::connect_handler(const boost::system::error_code& error) 
{ 
    if(!error) 
    { 
     std::cout << "Connection done" << std::endl; 
     m_flag = 1; 
    } 
    else 
    { 
     std::cout << "Error in connection: " << error.message() << std::endl; 
    } 
} 


//connect method 
bool MyClass::connect(std::string const & host, uint16_t port) 
{ 
    boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(host),port); 

    m_socket.async_connect(endpoint, 
      boost::bind(&MyClass::connect_handler, this, 
      boost::asio::placeholders::error)); 

    m_socket.get_io_service().run();//Wait async_connect and connect_handler to finish 

    if (m_flag == 0) return false; 
    else return true; 
} 


std::shared_ptr<MyClass> MyClass::create(std:: string const & host, uint16_t port) 
{ 
    boost::asio::io_service ios; 

    std::shared_ptr<MyClass> ptr(new MyClass(ios)); 

    bool bol = ptr->connect(host, port); 
    ptr->read(); 

    //while(1){} 

    if(bol == true) 
    { 
     //connection success, reading currently listening, pointer is returned to the user 
     return ptr; 
    } 
    else 
    { 
     //connection failure, pointer is still returned to the user but not listening as he's not connected 
     return ptr; 
    } 
} 

Und mein Haupt:

#include <boost/date_time/posix_time/posix_time.hpp> 
#include <boost/asio.hpp> 
#include "MyClass.hpp" 

int main() 
{ 
    try 
    { 
    std::cout << "Creation of instance" << std::endl; 

    std::shared_ptr <MyClass> var = MyClass::create("127.0.0.1", 8301); 

    std::cout << "Instance created" << std::endl; 



    } 
    catch (std::exception& e) 
    { 
     std::cerr << e.what() << std::endl; 
    } 

    return 0; 
} 
+0

Weil Sie in 'MyClass :: create' einen temporären' boost :: asio :: io_service' erstellen, der zerstört wird, bevor Sie 'run' oder' poll' darauf aufrufen können. Versuchen Sie es in 'main' zu erstellen, übergeben Sie es an' MyClass :: create' und rufen Sie danach 'run()' darauf auf. – kenba

+0

@kenba anscheinend hatten Sie recht, aber ich habe auch einen Reset() auf meinem io_service vergessen, ich werde versuchen, ihn am Leben zu halten – PsykoBabar

+0

@PsykoBabar ist es Ihre Absicht, 'io_service :: run' wieder in' read() 'aufzurufen ? Um den 'io_service' am Leben zu erhalten, tun Sie was @kenba vorschlägt, rufen Sie aber' read() 'von' connect_handler' auf. Auf diese Weise wird 'read()' aufgerufen, nachdem die Verbindung erfolgreich hergestellt wurde. Gerade jetzt wird 'read()' aufgerufen, ob eine Verbindung besteht oder nicht. Ich weiß, dass dies wahrscheinlich Debug-Code ist und Sie lesen nicht aus dem Socket in 'read()', aber Sie müssen auf keinen Fall den 'io_service' zurücksetzen und' run' erneut aufrufen. – aichao

Antwort

0

ich herausgefunden, wie mein Problem zu lösen.

Ich hatte in der Tat Probleme mit io_service zerstört nach "create" -Methode, so dass der Zeiger im Wesentlichen nicht weiter lesen konnte. Ich musste run() an einem Punkt aufrufen, um Callbacks zu starten, aber ich konnte es hauptsächlich nicht tun, da ich wollte, dass der Main weiterhin andere Dinge tut.

Also habe ich eine Klasse erstellt, die einen getrennten Thread startet und einen io_service enthält. Dieser Thread ruft run() regelmäßig auf. Es wurde dann als Attribut zu MyClass hinzugefügt.

Jetzt habe ich den Aufruf zu "create" einen Zeiger auf MyClass zurückgeben, der nicht beendet, was asynchrone Aufgabe in MyClass gestartet wurde.