mercredi 6 avril 2016

How to use a boost asio timer to handle a receive timeout

I'm trying to write a udp message heartbeat function with Boost asio. How would I create a boost asio timer that takes some action if a UDP message does NOT arrive within a prespecified timeout?

Right now I have a boost asio application that fires a udp status datagram message based off a timer boost::asio::steady_timer that fires @1HZ. I need the counterpart receiving application to take some action, i.e. (log a warning) if the packets do not arrive within a 2 second window (for ex).

For clarity here are the relevant parts of my heartbeat status sender application. It uses the following heartbeat timer callback to send the datagrams.

std::unique_ptr<boost::asio::steady_timer> mpStatusTimer;

void
Daemon::heartBeatTimer(
    const milliseconds& rHeartBeatMs)
{
    static auto& gEvtLog = gpLogger->getLoggerRef(
        Logger::LogDest::EventLog);
    // changed from absolute expires_at (previous + rHeartBeatMs) to
    // expires_from_now to account for background change in the system
    // time from the CMC
    mpStatusTimer->expires_from_now(rHeartBeatMs);
    mpStatusTimer->async_wait(boost::bind(
        &Daemon::heartBeatTimer, this, rHeartBeatMs));
    // send status udp packet
    mpTransmitSocket->async_send_to(
        buffer(mpStatusMessage.get(),
            sizeof(MemberSystemStatusMessage)),
            mEndpoint, boost::bind(
            &Daemon::handle_send_status,
            this, _1, _2));
}

And the async send callback is as follows: Note that the timer keeps the asio's IO_Service busy by reprogramming the timer each time - thus the handle_send_status does not need to do anything to the IOService

void
Daemon::handle_send_status(
    const boost::system::error_code& error,
    std::size_t bytes_transferred)
{
    static auto& gEvtLog = gpLogger->getLoggerRef(
        Logger::LogDest::EventLog);
    if (!error || (error == boost::asio::error::message_size)) {
        if (bytes_transferred == sizeof(StatusMessage)) {
            // log the message only if changed
            if (!mpLastStatusMessage || 
                (*mpLastStatusMessage != *mpStatusMessage)) {
                LOG_EVT_INFO(gEvtLog) << *mpStatusMessage;
                // update the last status message
                mpLastStatusMessage = std::make_unique<
                    StatusMessage>(*mpStatusMessage);
            }
            mpStatusMessage->incrementSequenceCounter();
        } else {
            LOG_EVT_ERROR(gEvtLog)
                << "unexpected datagram sent: size ["
                << bytes_transferred << "] bytes";
        }
    } else {
        LOG_EVT_ERROR(gEvtLog) << "handle_send: asio error code["
            << error.value() << "]";
    }
}

Aucun commentaire:

Enregistrer un commentaire