问题
I thought I had found the answer in the following example, but not quite.
boost::asio::ip::udp::socket socket(io_service);
...
boost::asio::ip::address_v4 local_interface =
boost::asio::ip::address_v4::from_string("1.2.3.4");
boost::asio::ip::multicast::outbound_interface option(local_interface);
socket.set_option(option);
How do I map eth0
to the appropriate outbound_interface option?
回答1:
The following code works fine on Windows and Mac OS X:
const ip::udp::resolver::query queryIF( ip::udp::v4(),
_description->getInterface(), "0" );
const ip::udp::resolver::iterator interfaceIP =
resolver.resolve( queryIF );
if( interfaceIP == end )
return false;
const ip::address ifAddr( ip::udp::endpoint( *interfaceIP ).address( ));
_read->set_option( ip::multicast::join_group( mcAddr.to_v4(),
ifAddr.to_v4( )));
_write->set_option( ip::multicast::outbound_interface( ifAddr.to_v4()));
EDIT: I had some issues on Linux, but did not look into it yet. My guess is the socket option is ignored in favor of the routing table.
回答2:
I think the reason why your example and eile's example don't work is because you didn't set the SO_BINDTODEVICE socket option.
See this to know why it doesn't work: http://codingrelic.geekhold.com/2009/10/code-snippet-sobindtodevice.html
See this to know how to do it with boost::asio: http://permalink.gmane.org/gmane.comp.lib.boost.asio.user/2724
回答3:
/**************************************************************************//**
\brief
\details
*******************************************************************************/
class UDPClient : public BoostSocketClient
{
public:
UDPClient ();
virtual ~UDPClient();
virtual ARLErrorCode_e open(int port_num, const char* network_type="ipv4", const char* ip_address="", uint32_t listen_interface=0);
virtual ARLErrorCode_e send(u8* message, u32 size);
virtual ARLErrorCode_e close();
virtual bool isOpen();
//virtual void onReceived(u8*, u32);
private:
void startReceive();
void handleReceive(const boost::system::error_code&, std::size_t);
void handleSend(const boost::system::error_code& error, std::size_t bytes_transferred);
private:
boost::asio::io_service send_ios_;
std::unique_ptr<boost::asio::io_service::work> send_worker_;
boost::asio::io_service receive_ios_;
std::unique_ptr<boost::asio::io_service::work> receive_worker_;
boost::thread send_thread_;
boost::thread receive_thread_;
boost::array<u8, 1024> _buffer;
boost::asio::ip::udp::endpoint send_endpoint_;
boost::asio::ip::udp::endpoint sender_endpoint_;
boost::asio::ip::udp::endpoint listen_endpoint_;
std::unique_ptr<boost::asio::ip::udp::socket> send_udp_socket_;
std::unique_ptr<boost::asio::ip::udp::socket> receive_udp_socket_;
};
#include <ACCompLib/Include/Typedefs.h>
#include <ACCompLib/Include/ARLErrorCodes.h>
#include <NetLib/Platform/Boost/cpp/UDPClient.h>
#include "Ws2tcpip.h"
#include "Iphlpapi.h"
using namespace std;
using namespace boost;
using namespace asio;
using namespace ip;
using namespace NetLib;
/***************************************************************************//**
\brief Constructor
\details
*******************************************************************************/
UDPClient::UDPClient()
{
receive_worker_.reset(new boost::asio::io_service::work(receive_ios_));
}
/***************************************************************************//**
\brief ctor
\details
*******************************************************************************/
UDPClient::~UDPClient()
{
try
{
receive_worker_.reset();
//send_worker_.reset();
if (send_thread_.joinable()) {
send_thread_.join();
}
if (receive_thread_.joinable()) {
receive_thread_.join();
}
}
catch (std::exception& e)
{
std::string str = e.what();
}
}
/***************************************************************************//**
\brief
\details
\note
\param[in]
*******************************************************************************/
ARLErrorCode_e UDPClient::open(int port_num, const char* network_type, const char* multicastAddress, uint32_t listen_interface)
{
try
{
struct in_addr in;
in.S_un.S_addr = listen_interface;
char* address_listen = inet_ntoa(in);
//const char* address_listen = "0.0.0.0";
std::string address_mcast = multicastAddress;
unsigned short address_port = port_num;
boost::system::error_code ec;
boost::asio::ip::address listen_addr = boost::asio::ip::address::from_string(address_listen, ec);
boost::asio::ip::address mcast_addr = boost::asio::ip::address::from_string(address_mcast, ec);
if (strcmp(network_type, "ipv4") == 0)
{
listen_endpoint_ = udp::endpoint(listen_addr, port_num);
send_endpoint_ = udp::endpoint(mcast_addr, port_num);
}
else if (strcmp(network_type, "ipv6") == 0)
{
}
else
return ES35_INVALID_SOCKET_CONNECTION;
send_udp_socket_.reset(new boost::asio::ip::udp::socket(send_ios_));
receive_udp_socket_.reset(new boost::asio::ip::udp::socket(receive_ios_));
send_udp_socket_->open(boost::asio::ip::udp::v4());
receive_udp_socket_->open(listen_endpoint_.protocol());
send_udp_socket_->set_option(boost::asio::ip::udp::socket::reuse_address(true));
receive_udp_socket_->set_option(boost::asio::ip::udp::socket::reuse_address(true));
boost::asio::ip::address_v4 local_interface =
boost::asio::ip::address_v4::from_string(address_listen);
boost::asio::ip::multicast::outbound_interface option(local_interface);
// Join the multicast group.
receive_udp_socket_->set_option(
boost::asio::ip::multicast::join_group(mcast_addr));
send_udp_socket_->set_option(option);
receive_udp_socket_->set_option(option);
boost::asio::ip::multicast::hops hops_option(3);
//send_udp_socket_->set_option(hops_option);
receive_udp_socket_->set_option(hops_option);
receive_udp_socket_->bind(listen_endpoint_);
startReceive();
receive_thread_ = boost::thread(boost::bind(&boost::asio::io_service::run, &receive_ios_));
send_thread_ = boost::thread(boost::bind(&boost::asio::io_service::run, &send_ios_));
return ES_NoError;
}
catch (std::exception& exp)
{
std::string str = exp.what();
return ES35_INVALID_SOCKET_CONNECTION;
}
}
/***************************************************************************//**
\brief
\details
*******************************************************************************/
ARLErrorCode_e UDPClient::close(void)
{
try {
boost::system::error_code ec;
//udp_socket_->cancel();
//udp_socket_.shutdown(socket_base::shutdown_both, ec);
if (ec)
{
return ES35_INVALID_SOCKET_CONNECTION;
}
if (send_udp_socket_->is_open())
{
send_udp_socket_->close();
}
if (receive_udp_socket_->is_open())
{
receive_udp_socket_->close();
}
receive_udp_socket_.reset();
send_udp_socket_.reset();
}
catch (std::exception& e)
{
std::string str = e.what();
return ES35_INVALID_SOCKET_CONNECTION;
}
return ES_NoError;
}
/***************************************************************************//**
\brief
\details
*******************************************************************************/
bool UDPClient::isOpen()
{
return send_udp_socket_->is_open() && receive_udp_socket_->is_open();
}
/***************************************************************************//**
\brief Send a message.
\details The message is sent asynchronously.
\param message
\param message size
*******************************************************************************/
ARLErrorCode_e UDPClient::send(u8* message, u32 size)
{
if (!isOpen()) {
return ES35_INVALID_SOCKET_CONNECTION;
}
std::string send_to_address = send_endpoint_.address().to_string();
send_udp_socket_->set_option(asio::ip::multicast::enable_loopback(false));
send_udp_socket_->async_send_to(
buffer(message, size),
send_endpoint_,
bind(
&UDPClient::handleSend,
this,
asio::placeholders::error,
asio::placeholders::bytes_transferred));
return ES_NoError;
}
/***************************************************************************//**
\brief Do nothing.
\details This function has the required signature to be used as an
asynchronous send completion handler.
\param not used
\param not used
*******************************************************************************/
void UDPClient::handleSend(const system::error_code& error, size_t)
{
if (error)
{
BoostSocketClient::onError(ES35_UDP_SEND_ERROR, (u8*)error.message().c_str(), error.message().size());
}
else
{
send_udp_socket_->set_option(asio::ip::multicast::enable_loopback(true));
}
}
/***************************************************************************//**
\brief Start an asynchronous receiver.
*******************************************************************************/
void NetLib::UDPClient::startReceive()
{
receive_udp_socket_->async_receive_from(
buffer(_buffer),
sender_endpoint_,
bind(
&UDPClient::handleReceive,
this,
asio::placeholders::error,
asio::placeholders::bytes_transferred));
std::string sender_address = sender_endpoint_.address().to_string();
}
/***************************************************************************//**
\brief Pass received data to the base class.
\details A new receiver is started.
\param error code
\param data size
*******************************************************************************/
void NetLib::UDPClient::handleReceive(const system::error_code& error, size_t size)
{
if (!error || error == error::message_size)
{
BoostSocketClient::onReceived(_buffer.data(), size);
startReceive();
}
else
{
BoostSocketClient::onError(ES35_UDP_RECEIVE_ERROR, (u8*)error.message().c_str(), error.message().size());
}
}
This code is not receiving response.please check
回答4:
http://permalink.gmane.org/gmane.comp.lib.boost.asio.user/2724 is invalid. The following code seems to be invalid:
boost::asio::ip::address_v4 local_interface =
boost::asio::ip::address_v4::from_string(ip);
boost::asio::ip::multicast::outbound_interface option(local_interface);
sock.set_option(option);
来源:https://stackoverflow.com/questions/8593859/boost-asio-socket-multicast-to-a-specific-ethernet-interface