Eumcoz
Eumcoz

Reputation: 2458

Timeouts on read and writes

I have been searching for a way to cancel a Boost ASIO read or write operation if it takes over a certain amount of time. My server is sending out HTTP requests, and reading results from those requests, so I originally had coded it as a synchronous read/write, and if it took so long, I would just carry on and ignore the results when they came back. This caused a problem if a server went down, my server would open to many sockets, and would crash. So I decided that I wanted to cancel the read/write if there was too long of a delay, but apparently synchronous read/writes are not able to be canceled without destroying the thread they are running in, which I do not want to do. So I found a post about how to mimic a synchronous read/write with asynchronous calls and cancel a call on time out. This is the post that I followed. I know this post is fairly old, so I am not sure if function calls have change since that version and the one I am working with(1.48), but this doesn't seem to be working quite right. Here is my code

bool connection::query_rtb(const std::string &request_information, std::string &reply_information)
{
    try
    {
        boost::optional<boost::system::error_code> timer1_result, timer2_result, write_result, read_result;
        boost::array<char,8192> buf;
        buf.assign(0);

        boost::asio::deadline_timer dt(io_service_);
        dt.expires_from_now(boost::posix_time::milliseconds(100));
        dt.async_wait(boost::bind(&connection::set_result, this, &timer1_result, _1, "timer1"));
        boost::asio::async_write(socket_, boost::asio::buffer(request_information, request_information.size()), boost::bind(&connection::set_result, this, &write_result, _1, "write"));
        io_service_.reset();

        while(io_service_.run_one())
        {
            if(write_result)
            {
                dt.cancel();
            }
            else if(timer1_result)
            {
                socket_.cancel();
            }
        }


        boost::asio::deadline_timer dt2(io_service_);
        dt2.expires_from_now(boost::posix_time::milliseconds(3000));
        dt2.async_wait(boost::bind(&connection::set_result, this, &timer2_result, _1, "timer2"));
        boost::asio::async_read(socket_, boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));
        //socket_.async_receive(boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));

        io_service_.reset();
        while(io_service_.run_one())
        {
            if(read_result)
            {
                dt2.cancel();
            }
            if(timer2_result)
            {
                socket_.cancel();
            }
        }


        reply_information = buf.data();
        std::cout << reply_information << std::endl;
        return true;
    }catch(std::exception& e)
    {
         std::cerr << e.what() << std::endl;
    }
}

void persistent_connection::set_result(boost::optional<boost::system::error_code> *a, boost::system::error_code ec, std::string t)
{
    std::cout << t << std::endl;
    a->reset(ec);
}

I was wondering if anyone see anything wrong with this code, or has any ideas on why it is not working. Currently the write seems to be fine, however the will not read until after the dt2 is done with it's timer. Please let me know if you need any more information, I will be glad to provide some.

Edit:

Seems like I got it working testing something I thought I previously tested. Using async_receive instead of async_read seems to have fixed whatever problem I was having. Any clue why this would cause I problem? I want to know if there is a problem with my logic or if that is how is async_read will usually act.

Upvotes: 1

Views: 120

Answers (1)

Sam Miller
Sam Miller

Reputation: 24174

boost::array<char,8192> buf;

...

boost::asio::async_read(socket_, boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));

You have instructed your program to read 8192 bytes from the socket. If switching the logic from using the async_read() free function to the async_receive() member function resolves this problem, consult the documentation

Remarks

The receive operation may not receive all of the requested number of bytes. Consider using the async_read function if you need to ensure that the requested amount of data is received before the asynchronous operation completes.

Upvotes: 1

Related Questions