2009-08-03 29 views
7

Aus irgendeinem Grund führt dies zu einer Zugriffsverletzung, jedoch keine detaillierte Dokumentation/Hilfe zu diesem Thema. Ich bin mir nicht sicher, wo ich es falsch mache. Seit dem, was ich auf der Boost-Site gesehen habe, sollte dies korrekt sein und den Inhalt jedes asio :: write-Aufrufs vom Client auf eine neue Zeile ausgeben. Der Client scheint gut zu funktionieren. Obwohl an dem Punkt der Server abstürzt, aber noch nichts gesendet hat.boost :: asio, asynchroner Lesefehler

Die Zugriffsverletzung tritt in Zeile 275 in basic_stream_socket.hpp auf. Die Ursache scheint zu sein, dass das Objekt (boost :: asio :: stream_socket_service) nicht initialisiert ist (der Wert des this-Zeigers ist 0xfeeefeee), aber ich don Ich verstehe nicht warum.

Die Programme Ausgabe:

Start server
Server::startAccept()
Server::handleAccept()
Connection accepted
Connection::startRead()
Server::startAccept()
Connection::handleRead()
READ ERROR: The I/O operation has been aborted because either a thread exited or an application request
Connection::startRead()

Der Code

#include "precompiled.h" 
#include "db.h" 
class Connection 
    : public boost::enable_shared_from_this<Connection> 
{ 
public: 
    typedef boost::shared_ptr<Connection> Pointer; 

    static Pointer create(boost::asio::io_service& ioService) 
    { 
     return Pointer(new Connection(ioService)); 
    } 

    ip::tcp::socket& getSocket() 
    { 
     return socket; 
    } 

    void startRead() 
    { 
     std::cout << "Connection::startRead()" << std::endl; 
     socket.async_read_some(boost::asio::buffer(readBuffer), 
      boost::bind(&Connection::handleRead,this,_1,_2)); 
    } 
private: 
    Connection(asio::io_service& ioService) 
     : socket(ioService) 
    { 
    } 

    void handleWrite(const boost::system::error_code&,size_t) 
    { 
    } 
    void handleRead(const boost::system::error_code&error,size_t len) 
    { 
     std::cout << "Connection::handleRead()" << std::endl; 
     if(error) 
     { 
      std::cout << "READ ERROR: "; 
      std::cout << boost::system::system_error(error).what(); 
      std::cout << std::endl; 
     } 
     else 
     { 
      std::cout << "read: "; 
      std::cout.write(readBuffer.data(),len); 
      std::cout << std::endl; 
     } 
     startRead(); 
    } 
    boost::array<char, 256> readBuffer; 
    ip::tcp::socket socket; 
}; 

class Server 
{ 
public: 
    Server(asio::io_service& ioService) 
     :acceptor(ioService, ip::tcp::endpoint(ip::tcp::v4(), getPort())) 
    { 
     startAccept(); 
    } 
private: 
    void startAccept() 
    { 
     std::cout << "RServer::startAccept()" << std::endl; 
     Connection::Pointer newConn = 
      Connection::create(acceptor.io_service()); 

     acceptor.async_accept(newConn->getSocket(), 
      boost::bind(&Server::handleAccept, this, newConn, 
      asio::placeholders::error)); 
    } 
    void handleAccept(Connection::Pointer newConn, 
     const boost::system::error_code& error) 
    { 
     std::cout << "Server::handleAccept()" << std::endl; 
     if(error) 
     { 
      std::cout << "CONNECTION ERROR: "; 
      std::cout << boost::system::system_error(error).what(); 
      std::cout << std::endl; 
     } 
     else 
     { 
      std::cout << "Connection accepted" << std::endl; 
      startAccept(); 
      newConn->startRead(); 
     } 
    } 
    ip::tcp::acceptor acceptor; 
}; 

int main() 
{ 
    std::cout << "Start server" << std::endl; 
    asio::io_service ioService; 
    RemoteAdminServer server(ioService); 
    boost::system::error_code error; 
    ioService.run(error); 
} 

Antwort

11

Sie sollten diesen Code-Schnipsel ändern:

void startRead() 
    { 
     std::cout << "Connection::startRead()" << std::endl; 
     socket.async_read_some(boost::asio::buffer(readBuffer), 
           boost::bind(&Connection::handleRead,this,_1,_2)); 
    } 

zu:

void startRead() 
{ 
    std::cout << "Connection::startRead()" << std::endl; 
    socket.async_read_some(boost::asio::buffer(readBuffer), 
       boost::bind(&Connection::handleRead,this->shared_from_this(),_1,_2)); 
} 

Beachten Sie, dass ich einen gemeinsamen Zeiger an bind übergeben habe. Dadurch bleibt Ihre Connection Instanz bis zum Aufruf des Handlers erhalten. Andernfalls wird die Verwendungszählung in Server::startAccept auf Null gesetzt und das Objekt gelöscht. Wenn der Handler dann aufgerufen wird, ist der Speicher ungültig und das gefürchtete "undefined Verhalten" tritt auf.

0

Ich denke, Ihr Lauf existiert, weil Sie keine Arbeit links in der Arbeitswarteschlange verfügen.

Sie müssen verhindern, dass der Lauf beendet wird und Ihr Serviceobjekt zerstört wird.

Entweder versuchen Sie dies:

boost::asio::io_service::work

oder einfach eine

do { ioService.run(error); } while(!error); 
+0

Es beendet nie run() trotzdem –

+0

Sie können 'io_service' nicht erneut ausführen, ohne es zurückzusetzen. –