将 asio 套接字多播提升到特定以太网接口

发布于 2024-12-22 06:08:03 字数 373 浏览 4 评论 0原文

我以为我在下面的例子中找到了答案,但并不完全是。

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);

如何将 eth0 映射到适当的 outbound_interface 选项?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

比忠 2024-12-29 06:08:03

以下代码在 Windows 和 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()));

编辑:我在 Linux 上遇到了一些问题,但还没有研究它。我的猜测是套接字选项被忽略,有利于路由表。

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.

十年九夏 2024-12-29 06:08:03

我认为您的示例和 eile 的示例不起作用的原因是您没有设置 SO_BINDTODEVICE 套接字选项。

请参阅此内容以了解为什么它不起作用:http://codingrelic。 geekhold.com/2009/10/code-snippet-sobindtodevice.html

请参阅此内容以了解如何使用 boost::asio: http://permalink.gmane.org/gmane.comp.lib.boost .asio.user/2724

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

千里故人稀 2024-12-29 06:08:03
/**************************************************************************//**
\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
/**************************************************************************//**
\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
遮云壑 2024-12-29 06:08:03

http://permalink.gmane.org/gmane.comp。 lib.boost.asio.user/2724 无效。
下面的代码似乎无效:

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);

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文