Получение многоадресных сообщений на ПК с многосетевой ОС Windows - PullRequest
2 голосов
/ 07 июня 2010

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

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

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

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

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

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

// socket_tst.cpp : Defines the entry point for the console application.
//

\#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;
  }

  // Create sockets
  if (INVALID_SOCKET == (m_socket = 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(); 
  }

  // Configure socket addresses
  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;

  //bind sockets
  if ( bind( m_socket, (SOCKADDR*) &m_sockAdr, sizeof(m_sockAdr) )  == SOCKET_ERROR )
  {
    return  WSAGetLastError();
  }

  // join multicast
  struct ip_mreq_source imr; 

  memset(&imr,0,sizeof(imr));
  imr.imr_multiaddr.s_addr  = m_multicastAdr; // address of multicastgroup
  imr.imr_sourceaddr.s_addr = 0;              // sourceaddress (not used)
  imr.imr_interface.s_addr  = m_interfaceAdr; // interface address
  /* first join multicast group, then registerer selected interface as 
  * multicast sending interface */
  if( setsockopt( m_socket 
                  ,IPPROTO_IP
                  ,IP_ADD_MEMBERSHIP
                  ,(char*) &imr
                  , sizeof(imr)) 
                  == SOCKET_ERROR)
  {
    return SOCKET_ERROR;
  }
  else
  {
    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("receiving msgs...\n");
  while(1)
  {
    // get inputbuffer from socket
    int sock_return = SOCKET_ERROR;
    sockaddr_in socketAddress;
    char buffer[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;
}

Спасибо за вашу помощь!

Ответы [ 2 ]

2 голосов
/ 09 июня 2010

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

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

1 голос
/ 07 июня 2010

Вы можете проверить / изменить свою таблицу маршрутизации.Там будет маршрут для многоадресного (224.0.0.0, подсеть 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

******
...