Boost Asio async_recieve_from multicast com use_future não funciona simultaneamente com async_send_to
ITNOA
Quero escrever programas que enviem e recebam multicast simultaneamente como abaixo
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;
}
Meu problema é por que result.wait () causa para gerar uma exceção?
a nota talvez importante é que quando eu removo message_sender.sendlinha, este programa não levanta nenhuma exceção e linha de result.wait()bloco até o final. mas quando a linha é message_sender.sendadicionada, este programa levanta uma exceção e não funciona corretamente.
Meu message_sender é igual a este código.
E meu message_receiver é como abaixo
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());
}
Onde está o meu erro?
Eu testo esse código nas plataformas abaixo
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
Respostas
Você está conseguindo no_stateporque geton futurepode ser chamado apenas uma vez.
Abaixo
std::make_pair(result.get() != 0, result.get());
get é chamado duas vezes.
Veja a referência :
Notas As implementações são encorajadas a detectar o caso quando valid () é falso antes da chamada e lançar um std :: future_error com uma condição de erro de std :: future_errc :: no_state.
Após a primeira chamada de get, validretorna false.