Получение многоадресных сообщений на многомодовом компьютере с ОС Windows

79
7

Я разрабатываю диагностический инструмент на ПК с несколькими сетевыми интерфейсами на основе multicast/udp. Пользователь может выбрать сетевой адаптер, приложение создает сокеты, связывает их с этим сетевым адаптером и добавляет их в определенную группу многоадресной рассылки.


Отправка сообщений многоадресной рассылки работает нормально. Однако получение сообщений выполняется только в том случае, если я привязываю сокеты к конкретному сетевому адаптеру моего ПК. Это почти похоже на то, что для получения сообщений многоадресной рассылки в Windows есть сетевой адаптер по умолчанию, который всегда является первым сетевым адаптером, возвращаемым функцией GetAdapterInfo.


Я отслеживал сеть с помощью Wireshark и обнаружил, что сообщение "Группа IGMP Join Group" не отправлено из NIC, в который я привязал сокет, но с помощью этой сетевой платы по умолчанию.


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


Мне удалось изменить этот сетевой адаптер по умолчанию, добавив дополнительную запись в таблицу маршрутизации моего ПК, но я не думаю, что это хорошее решение проблемы.


Проблема также возникает при использовании кода, приведенного ниже. Сообщения группы объединений не отправляются через 192.168.52, а через другую сетевую карту.


//socket_tst.cpp: Определяет точку входа для консольного приложения.
//


#include tchar.h
#include winsock2.h
#include ws2ipdef.h
#include IpHlpApi.h
#include IpTypes.h


#include stdio.h


int _tmain (int argc, _TCHAR * argv [])
{ WSADATA m_wsaData; SOCKET m_socket; sockaddr_in m_sockAdr; UINT16 m_port = 319; u_long m_interfaceAdr = inet_addr ( "192.168.1.52" ); u_long m_multicastAdr = inet_addr ( "224.0.0.107" );


int returnValue = WSAStartup (MAKEWORD (2,2), & m_wsaData); if (returnValue!= S_OK) {   return returnValue; }


//Создание сокетов if (INVALID_SOCKET == (m_socket = сокет (AF_INET, SOCK_DGRAM, IPPROTO_UDP))) {   return WSAGetLastError(); }


int doreuseaddress = TRUE; if (setsockopt (m_socket, SOL_SOCKET, SO_REUSEADDR, (char *) & doreuseaddress, sizeof (doreuseaddress)) == SOCKET_ERROR) {   return WSAGetLastError(); }


//Настройка адресов сокетов MemSet (& m_sockAdr, 0, SizeOf (m_sockAdr)); m_sockAdr.sin_family = AF_INET; m_sockAdr.sin_port = htons (m_port);
m_sockAdr.sin_addr.s_addr = m_interfaceAdr;


//связывать сокеты if (bind (m_socket, (SOCKADDR *) & m_sockAdr, sizeof (m_sockAdr)) == SOCKET_ERROR) {   return WSAGetLastError(); }


//присоединяем многоадресную рассылку struct ip_mreq_source imr;


MemSet (& IMR, 0, SizeOf (КМС)); imr.imr_multiaddr.s_addr = m_multicastAdr;//адрес многоадресной группы imr.imr_sourceaddr.s_addr = 0;//sourceaddress (не используется) imr.imr_interface.s_addr = m_interfaceAdr;//адрес интерфейса /* сначала присоедините группу многоадресной рассылки, а затем выбранный интерфейс * многоадресная передача интерфейс / if (setsockopt (m_socket                 , IPPROTO_IP                 , IP_ADD_MEMBERSHIP                 , (char) & imr                 , sizeof (imr))                 == SOCKET_ERROR) {   return SOCKET_ERROR; } еще {   if (setsockopt (m_socket                 , IPPROTO_IP                 , IP_MULTICAST_IF                 , (char *) & imr.imr_interface.s_addr                 , SizeOf (& imr.imr_interface.s_addr))                 == SOCKET_ERROR)   {     return SOCKET_ERROR;   } }


printf ( "получение msgs...\n" ); в то время как (1) {   // получить inputbuffer из сокета   int sock_return = SOCKET_ERROR;   sockaddr_in socketAddress;   буфер char [1500];


int addressLength = sizeof(socketAddress);
sock_return = recvfrom(m_socket, (char*) &buffer, 1500, 0, (SOCKADDR*)&socketAddress, &addressLength );
if( sock_return == SOCKET_ERROR)
{
int wsa_error = WSAGetLastError();
return wsa_error;
}
else
{
printf("got message!\n");
}

}


return 0;
}



Спасибо четыре твоей помощи!

спросил(а) 2021-01-19T15:25:00+03:00 9 месяцев, 1 неделя назад
1
Решение
80

Проблема была простой опечаткой.
Вместо использования структуры struct ip_mreq_source следует использовать структуру struct ip_mreq, если вы используете опцию IP_MULTICAST_IF. (Другая структура необходима для параметра IP_ADD_SOURCE_MEMBERSHIP)

Использование неправильной структуры, скорее всего, привело к тому, что функция setsockeopt обнаружила нуль, где ожидался IP-адрес NIC. Zero также является значением константы INADDR_ANY, которая выбирает сетевой адаптер по умолчанию.: -)

ответил(а) 2021-01-19T15:25:00+03:00 9 месяцев, 1 неделя назад
65

Возможно, вы захотите проверить/изменить таблицу маршрутизации. Там будет трафик для трафика многоадресной передачи (224.0.0.0, subnet 240.0.0.0) с его соответствующим показателем:

C:\Users\Cetra>netstat -rn

*****

IPv4 Route Table
===========================================================================
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.80.254 192.168.80.99 20
127.0.0.0 255.0.0.0 On-link 127.0.0.1 306
127.0.0.1 255.255.255.255 On-link 127.0.0.1 306
127.255.255.255 255.255.255.255 On-link 127.0.0.1 306
192.168.80.0 255.255.255.0 On-link 192.168.80.99 276
192.168.80.99 255.255.255.255 On-link 192.168.80.99 276
192.168.80.255 255.255.255.255 On-link 192.168.80.99 276

224.0.0.0 240.0.0.0 On-link 127.0.0.1 306
224.0.0.0 240.0.0.0 On-link 192.168.80.99 276

255.255.255.255 255.255.255.255 On-link 127.0.0.1 306
255.255.255.255 255.255.255.255 On-link 192.168.80.99 276

******

ответил(а) 2021-01-19T15:25:00+03:00 9 месяцев, 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема