1

I want to write program that send and receive multicast simultaneously like below

int main()
{
    const string group_address = "235.127.1.1";
    constexpr uint16_t PORT_NUMBER = 8765;

    boost::asio::io_context io_context;
    auto work_guard = boost::asio::make_work_guard(io_context);

    BoostMessageSender message_sender(group_address, "eth1", PORT_NUMBER, io_context);
    BoostMessageReceiver message_receiver(group_address, "eth1", PORT_NUMBER, io_context);

    std::thread t1([&io_context]()
        {
            cout << __LINE__ << endl;
            io_context.run();
        });

    this_thread::sleep_for(1s);

    std::array<char, 20> data = {};
    auto result = std::async(std::launch::async, [&message_receiver, &data]()
        {
                message_receiver.receive(gw::buffer(data));
                cout << " receive finished" << endl; // does not reach this line :(((
        });

    this_thread::sleep_for(1s);
    message_sender.send("Any body there!");

    result.wait(); // Raise exception what(): std::future_error: No associated state
    cout << "receive message: ";
    std::copy(std::begin(data),
          std::end(data),
          std::ostream_iterator<char>(std::cout, ""));

    io_context.stop();
    t1.join();
    return 0;
}

My problem is why result.wait() cause to raise exception?

the maybe important note that is when I remove message_sender.send line, this program does not raise any exception and line of result.wait() block until end. but when line of message_sender.send added, this program raise exception and does not work properly.

My message_sender is equal to this code.

And my message_receiver is like below

BoostMessageReceiver::BoostMessageReceiver(const std::string& group_address, const std::string& interface_name, uint16_t port_number, ba::io_context& io_context)
    : AbstractMessageReceiver(group_address, interface_name, port_number)
    , io_context(io_context)
    , listen_endpoint(ba::ip::address_v4::any(), port_number)
    , socket(io_context)
{
    socket.open(listen_endpoint.protocol());
    socket.set_option(ba::ip::udp::socket::reuse_address(true));
    socket.bind(listen_endpoint);

    // Join to multicast group
    socket.set_option(ba::ip::multicast::enable_loopback(true));
    socket.set_option(ba::ip::multicast::join_group(ba::ip::address::from_string(group_address)));
}

std::pair<bool, std::size_t> BoostMessageReceiver::receive(const AbstractMessageReceiver::MutableBuffer& buffer) noexcept
{
    ba::ip::udp::endpoint sender_endpoint;

    std::future<std::size_t> result = socket.async_receive_from(ba::buffer(buffer.data(), buffer.size()), sender_endpoint, ba::use_future);

    return std::make_pair(result.get() != 0, result.get());
}

Where is my wrong?

I test these code on below platforms

Visual Studio 2019 16.7.4
Windows 10 1909 latest update
Boost 1.73.0

Ubuntu 20.04.1 LTS
GCC 9.3.0
Boost 1.71.0

1 Answer 1

0

You are getting no_state because get on future can be called only once.

Below

std::make_pair(result.get() != 0, result.get());

get is called twice.

See reference:

Notes The implementations are encouraged to detect the case when valid() is false before the call and throw a std::future_error with an error condition of std::future_errc::no_state.

After first call of get, valid returns false.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.