jeudi 26 février 2015

set_option: Invalid argument when setting option boost::asio::ip::multicast::join_group inside lambda

This code is intended to receive UDP multicast messages using Boost.Asio. A Boost system_error exception is thrown by the code below when the second set_option() call inside receiver's constructor is made (to join the multicast group). The complaint is "Invalid argument". This seems to be related to the fact that the constructor occurs inside a lambda defined inside IO::doIO(), because using a member for the std::thread with identical functionality (IO::threadFunc()) instead results in the expected behavior (no exceptions thrown).


Why is this, and how can I fix it so that I may use a lambda?



//g++ -std=c++11 doesntWork.cc -lboost_system -lpthread

#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

class IO
{
public:
class receiver
{
public:
receiver(
boost::asio::io_service &io_service,
const boost::asio::ip::address &multicast_address,
const unsigned short portNumber) : _socket(io_service)
{
const boost::asio::ip::udp::endpoint listen_endpoint(
boost::asio::ip::address::from_string("0.0.0.0"), portNumber);

_socket.open(listen_endpoint.protocol());
_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
_socket.bind(listen_endpoint);
std::cerr << " About to set option join_group" << std::endl;
_socket.set_option(boost::asio::ip::multicast::join_group(
multicast_address));

_socket.async_receive_from(
boost::asio::buffer(_data),
_sender_endpoint,
boost::bind(&receiver::handle_receive_from, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}

private:
void handle_receive_from(
const boost::system::error_code &error,
const size_t bytes_recvd)
{
if (!error)
{
for(const auto &c : _data)
std::cout << c;
std::cout << std::endl;
}
}

private:
boost::asio::ip::udp::socket _socket;
boost::asio::ip::udp::endpoint _sender_endpoint;
std::vector<unsigned char> _data;
}; // receiver class


void doIO()
{
const boost::asio::ip::address multicast_address =
boost::asio::ip::address::from_string("235.0.0.1");

const unsigned short portNumber = 9999;

// _io_service_thread = std::thread(
// &IO::threadFunc, this, multicast_address, portNumber);

_io_service_thread = std::thread([&, this]{
try {
// Construct an asynchronous receiver
receiver r(_io_service, multicast_address, portNumber);

// Now run the IO service
_io_service.run();
}
catch(const boost::system::system_error &e)
{
std::cerr << e.what() << std::endl;
throw e; //std::terminate()
}
});
}

void threadFunc(
const boost::asio::ip::address &multicast_address,
const unsigned short portNumber)
{
try {
// Construct an asynchronous receiver
receiver r(_io_service, multicast_address, portNumber);

// Now run the IO service
_io_service.run();
}
catch(const boost::system::system_error &e)
{
std::cerr << e.what() << std::endl;
throw e; //std::terminate()
}
}

private:
boost::asio::io_service _io_service;
std::thread _io_service_thread;
}; // IO class

int main()
{
IO io;
io.doIO();

std::cout << "IO Service is running" << std::endl;

sleep(9999);
}

Aucun commentaire:

Enregistrer un commentaire