0

In boost website, there is a good example about timeout of async operations. However, in that example, the socket is closed to cancel operations. There is also socket::cancel(), but in both documentation and as a compiler warning, it is stated as problematic in terms of portability.

Among the stack of Boost.Asio timeout questions in SO, there are several kind of answers. The first one probably is introducing a custom event loop, i.e., loop io_service::run_one() and cancel the event loop on deadline. I am using io_service::run() in a worker thread. That's not the kind of solution I would like to employ, if possible, as I do not want to change my code base.

A second option is directly changing the options of native socket. However, I would like to stick to Boost.Asio if possible and avoid any sort of platform-specific code as much as possible.

The example in the documentation is for an old version of Boost.Asio, but it's working properly, other than being forced to close the socket to cancel the operations. Using the documentation example, I have the following

void check_deadline(const boost::system::error_code &ec)
{
    if(!running) {
       return;
    }

    if(timer.expires_at() <= boost::asio::deadline_timer::traits_type::now()) {

        // cancel all operations
        boost::system::error_code errorcode;
        boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();
        socket.close(errorcode);
        if(errorcode) {
            SLOGERROR(mutex, errorcode.message(), "check_deadline()");
        }
        else {
            SLOG(mutex, "timed out", "check_deadline()");

            // connect again
            Connect(endpoint);
            if(errorcode) {
                SLOGERROR(mutex, errorcode.message(), "check_deadline()");
            }
        }

        // set timer to infinity, so that it won't expire
        // until a proper deadline is set
        timer.expires_at(boost::posix_time::pos_infin);
    }

    // keep waiting
    timer.async_wait(std::bind(&TCPClient::check_deadline, this, std::placeholders::_1));
}

This is the only callback function registered to async_wait.The very first solution I could come up is reconnecting after closing the socket. Now my question is, is there a better way? By better way, I mean canceling the operations based on a timer without actually disrupting (i.e., not closing the socket) the connection.

Cengiz Kandemir
  • 375
  • 1
  • 4
  • 16
  • Why would you want to cancel an async IO but not close the socket? What is your use case? – rustyx Jul 31 '16 at 14:49
  • I want ability to cancel an operation, but perform another one without connecting again. I may or may not use this functionality, but I want it regardless as it seems trivial. For the record, socket.cancel() is working, but I am not sure how portable it is. – Cengiz Kandemir Jul 31 '16 at 15:07
  • Gracefully handling timeouts is often not trivial (see [this](http://stackoverflow.com/a/26249540/1053968) answer for considerations one may take). The prescribed way for portability is documented [here](http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_stream_socket/cancel/overload1.html). Personally, I prefer to make the application protocol resilient to connectivity issues, and often leverage the resiliency for timeouts. Also, using socket options for timeouts rarely helps (see [here](http://stackoverflow.com/a/30428941/1053968)). – Tanner Sansbury Aug 01 '16 at 14:03

0 Answers0