简体   繁体   中英

How to make a timeout at receiving in boost::asio udp::socket?

I create an one-thread application which exchanges with another one via UDP. When the second is disconnecting, my socket::receive_from blocks and I don't know how to solve this problem not changing the entire program into multi-threads or async interactions.

I thought that next may be a solution:

std::chrono::milliseconds timeout{4};
boost::system::error_code err;
data_t buffer(kPackageMaxSize);
std::size_t size = 0;

const auto status = std::async(std::launch::async,
    [&]{
        size = socket_.receive_from(boost::asio::buffer(buffer), dst_, 0, err);
    }
).wait_for(timeout);

switch (status)
{
    case std::future_status::timeout: /*...*/ break;
}

But I achieved a new problem: Qt Creator (GDB 11.1) (I don't have ability to try something yet) began to fall when I am debugging. If it runs without, the solution also not always works.

PS. As for "it doesn't work when debugging", debugging (specifically breakpoints) obviously changes timing. Also, keep in mind.network operations have varying latency and UDP isn't a guaranteed protocol: messages may not be delivered.


Asio stands for "Asynchronous IO". As you might suspect, this means that asynchronous IO is a built-in feature, it's the entire purpose of the library. See overview/core/async.html: Concurrency Without Threads

It's not necessary to complicate with std::async . In your case I'd suggest using async_receive_from with use_future , as it is closest to the model you opted for:

Live On Coliru

#include <boost/asio.hpp>
#include <iostream>
#include <iomanip>
namespace net = boost::asio;
using net::ip::udp;

using namespace std::chrono_literals;
constexpr auto kPackageMaxSize = 65520;
using data_t = std::vector<char>;

int main() {
    net::thread_pool ioc;

    udp::socket socket_(ioc, udp::v4());
    socket_.bind({{}, 8989});

    udp::endpoint ep;
    data_t        buffer(kPackageMaxSize);
    auto          fut =
        socket_.async_receive_from(net::buffer(buffer), ep, net::use_future);

    switch (fut.wait_for(4ms)) {
        case std::future_status::ready: {
            buffer.resize(fut.get()); // never blocks here
            std::cout << "Received " << buffer.size() << " bytes: "
                      << std::quoted(
                             std::string_view(buffer.data(), buffer.size()))
                      << "\n";
            break;
        }
        case std::future_status::timeout:
        case std::future_status::deferred: {
            std::cout << "Timeout\n";
            socket_.cancel(); // stop the IO operation
            // fut.get() would throw system_error(net::error::operation_aborted)
            break;
        }
    }

    ioc.join();
}

The Coliru output:

Received 12 bytes: "Hello World
"

Locally demonstrating both timeout and successful path:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM