Pregunta

Estoy desarrollando una herramienta de diagnóstico en una PC con varias interfaces de red basadas en multidifusión/UDP. El usuario puede seleccionar una NIC, la aplicación crea sockets, los vincula a esta NIC y los agrega al grupo de multidifusión específico.

El envío de mensajes de multidifusión funciona bien. Sin embargo, la recepción de mensajes solo tiene éxito si encuentro los enchufes a una NIC específica de mi PC. Casi se parece a una NIC 'predeterminada' para recibir mensajes de multidifusión en Windows, que siempre es el primer NIC devuelto por el GetAdapterinfo función.

Monitoricé la red con Wireshark y descubrí que el mensaje "Grupo de unión IGMP" no se envía desde la NIC que ato el socket, pero con esta NIC 'predeterminada'.

Si deshabilo esta NIC (o elimino el cable de red), la siguiente NIC de la lista devuelta por GetAdapterInfo se usa para recibir mensajes de multidifusión.

Tuve éxito al cambiar esta NIC 'predeterminada' agregando una entrada adicional a la tabla de enrutamiento de mi PC, pero no creo que esta sea una buena solución del problema.

El problema también ocurre con el código adjunto a continuación. Los mensajes de unión del grupo no se envían a través de 192.168.52 pero a través de una NIC diferente.

// 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;
}

¡Gracias cuatro de tu ayuda!

¿Fue útil?

Solución

El problema era un error tipográfico simple. En lugar de usar la estructura struct ip_mreq_source, la estructura struct ip_mreq debe usarse si se usa la opción IP_MULTICAST_IF. (La otra estructura es necesaria para la opción ip_add_source_membership)

El uso de la estructura incorrecta probablemente tuvo el resultado de que la función setSockeopt encontró un cero donde se esperaba la dirección IP de NIC. Zero también es el valor de la constante inAddr_ alguna, que elige la NIC predeterminada del sistema. :-)

Otros consejos

Es posible que desee verificar/cambiar su tabla de enrutamiento. Habrá una ruta para el tráfico de multicast (224.0.0.0, subred 240.0.0.0) con su métrica apropiada:

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

******
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top