Adam Magaluk
Adam Magaluk

Reputation: 1726

Boost.Asio deadline_timer not working as expected

I'm trying to implement a timeout for a Boost.Asio read on a TCP socket.

I am trying to use a async_read_some with a deadline_timer. My function below is a member of a class that holds a smart pointer to the TCP socket and io_service. What I would expect to happen when called on an active socket that doesn't return any data is wait 2 seconds and return false.

What happens is: If the socket never returns any data it works as expected. How ever if the server returns the data the proceeding calls to the method below return immediately because to timers callback is called without waiting the two seconds.

I tried commenting out the async_read_some call and the function always works as expected. Why would async_read_some change how the timer works?

    client::client() {
        // Init socket and timer
        pSock = boost::shared_ptr<tcp::socket > (new tcp::socket(io_service));
    }

bool client::getData() {

              // Reset io_service
                io_service.reset(); 

                // Init read timer
                boost::asio::deadline_timer timer(pSock->io_service());
                timer.expires_from_now(boost::posix_time::seconds(2)); 
                timer.async_wait(boost::bind(&client::read_timeout, this, boost::system::error_code(), true));


    //            // Async read the data
                pSock->async_read_some(boost::asio::buffer(buffer_),
                        boost::bind(&client::read_complete,
                        this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred
                        ));



                // While io_service runs check read result 
                while (pSock->io_service().run_one()) {
                    if (m_read_result > 0) {
                        // Read success 
                        return m_read_result;
                    }else if(m_read_result < 0){
                        return false;
                    }
                }
            }
}



void client::read_complete(const boost::system::error_code& error, size_t bytes_transferred) {
    if (!error) {
        m_read_result = bytes_transferred;
    }else{
        m_read_result = -1;
    }
}

void client::read_timeout(const boost::system::error_code& error, bool timeout) {
    if(!error){
        m_read_result = -1;
    }
}

Upvotes: 2

Views: 4330

Answers (2)

Adam Magaluk
Adam Magaluk

Reputation: 1726

Simple problem when setting up the timer boost::system::error_code() should be changed to _1 or a error::placeholder

timer.async_wait(boost::bind(&client::read_timeout, this, _1, true));

Upvotes: 1

Rafał Rawicki
Rafał Rawicki

Reputation: 22690

You have negated condition when you check for connection errors.

It should be:

if(error){
    std::cout  << "read_timeout Error - " << error.message() << std::endl;
}

Now you will see, that the callback is invoked with error code boost::asio::error::operation_aborted.

This is because, when you receive any data, you return from function getData and deadline_timer's destructor calls the callback with the error code set.

Upvotes: 0

Related Questions