Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::asio, asynchronous read error

For some reason this results in an access violation, however not having any detailed documentation/help on this I'm not sure where I'm doing it wrong. Since going by what I've seen on the boost site this should be correct, and print the contents of each asio::write call from the client to a new line. The client seems to work fine. Although at the point the server crashes, but it hasn't sent anything yet.

The access violation occurs in basic_stream_socket.hpp on line 275. The cause seems to be that the object (boost::asio::stream_socket_service) is not initialized (the value of the this pointer is 0xfeeefeee), however I don't see why it isn't.

The programs output:

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()

The 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);
}
like image 662
Fire Lancer Avatar asked Aug 03 '09 15:08

Fire Lancer


People also ask

What is Boost :: ASIO :: io_service?

Asio's io_service is the facilitator for operating on asynchronous functions. Once an async operation is ready, it uses one of io_service 's running threads to call you back. If no such thread exists it uses its own internal thread to call you. Think of it as a queue containing operations.

What is C++ Boost ASIO?

Boost. Asio is a cross-platform C++ library for network and low-level I/O programming that provides developers with a consistent asynchronous model using a modern C++ approach. Overview. An overview of the features included in Boost. Asio, plus rationale and design information.

Is Boost ASIO thread safe?

Thread Safety Like a regular Boost. Asio socket, a stream is not thread safe. Callers are responsible for synchronizing operations on the socket using an implicit or explicit strand, as per the Asio documentation.

Does Boost ASIO use Epoll?

For me, main advantage of Boost. Asio (besides cross-platform work) is, that on each platform, it uses most effective strategy ( epoll on Linux 2.6, kqueue on FreeBSD/MacOSX, Overlapped IO on MS Windows).


1 Answers

You should change this code snippet:

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

to:

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));
}

Notice that I passed a shared pointer to bind. This will keep your Connection instance around until the handler is invoked. Otherwise, the use count goes to zero in Server::startAccept and the object is deleted. Then, when the handler is invoked, the memory is invalid and you experience the dreaded "undefined behavior."

like image 159
Dan Avatar answered Oct 15 '22 13:10

Dan