Привязать сокет к определенному интерфейсу с неизвестным IP

У меня хост с двумя интерфейсами. В моем конкретном случае я пытаюсь присоединиться к группе многоадресной рассылки, используя boost::asio::ip::multicast::join_group, который, похоже, работает только в том случае, если я использую конструктор, включающий локальный адрес. Однако я заранее не знаю IP-адрес локального интерфейса, подключенного к удаленному хосту, который будет выполнять многоадресную рассылку. Однако я знаю, что это будет eth1. Конечно, я мог бы сделать его настраиваемым, но это похоже на введение бесполезной возможности неправильной настройки, видя, как один и тот же адрес должен быть настроен для интерфейса и моего приложения.

В идеале был бы очевидный способ создать boost::asio::endpoint или boost::asio::address из интерфейса вместо адреса, который я как-то пропустил. В качестве альтернативы я, конечно, был бы так же доволен любым другим способом вывести интерфейс IP, который работает как с DHCP-сервером, так и без него.

Есть ли правильный способ сделать то или иное, или я просто должен доверять пользователям, чтобы они никогда не возились с конфигурацией?

Чтобы убедиться, что это не полностью проблема XY, вот код, который я использовал во время тестирования для присоединения к группе многоадресной рассылки:

m_socket.open(boost_ip::udp::v4());
m_socket.bind(boost_ip::udp::endpoint(boost_ip::udp::v4(), listeningPort));

m_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
m_socket.set_option(boost::asio::ip::multicast::join_group(
                  boost::asio::ip::address::from_string("225.x.x.10").to_v4(),  // remote
                  boost::asio::ip::address::from_string("192.x.x.3").to_v4())); // local

Это работает, но когда я отбрасываю последнюю строку, чтобы она не зависела от текущего локального адреса (который может быть изменен при развертывании), я больше не получаю никаких пакетов.


person DeVadder    schedule 09.03.2015    source источник


Ответы (2)


Многоадресная рассылка использует протокол IGMP для формирования группы многоадресной рассылки. Поскольку IGMP работает на сетевом уровне, ему требуется локальный IP-адрес конечной точки, которая присоединяется к группе многоадресной рассылки.

Приложение должно дождаться события, указывающего, что IP-адрес был назначен интерфейсу Ethernet, а затем вызвать метод join_group, чтобы присоединиться к группе многоадресной рассылки.

person Vivek    schedule 09.03.2015
comment
Я могу с уверенностью предположить, что IP-адрес больше не будет изменен после запуска приложения. Но что было бы хорошим способом найти текущий Ip интерфейсов, если я не знаю, используется ли DHCP или нет? - person DeVadder; 10.03.2015
comment
Здесь обсуждается программное получение IP-адреса: ссылка < / а> - person Vivek; 12.03.2015

Я сам придумал ответ на свой вопрос. Это работает для меня, но я оставлю вопрос открытым, если у кого-то есть более простое решение.

Я решил использовать <ifaddrs.h>, чтобы просто найти мой текущий IP-адрес интерфейса и использовать его для присоединения к группе многоадресной рассылки. Это код, который я использовал для определения своего ip:

#include <ifaddrs.h>
#include <boost/asio.hpp>
#include <cstring>

std::string getInterfaceAddress(const std::string & interfaceName)
{
    ifaddrs* firstNetIf = 0;
    getifaddrs(&firstNetIf);

    ifaddrs* netIf = 0;
    for(netIf = firstNetIf; netIf != 0; netIf = netIf->ifa_next)
    {
        if(netIf->ifa_addr->sa_family == AF_INET && std::strncmp(netIf->ifa_name, interfaceName.c_str(), interfaceName.length()) == 0)
        {
            break;
        }
    }

    unsigned long address =
            netIf != 0 ? reinterpret_cast<sockaddr_in*>(netIf->ifa_addr)->sin_addr.s_addr : 0;

    if(firstNetIf != 0)
    {
        freeifaddrs(firstNetIf);
    }

    return boost::asio::ip::address_v4(htonl(address)).to_string();
}

Конечно, в моем случае я мог бы сравнить с "eth1" и вернуть boost::asio::ip::address напрямую, но оказалось, что этот код можно использовать и в другом месте таким же образом.

person DeVadder    schedule 10.03.2015