Domanda

sto sviluppando uno strumento di diagnostica su un PC con interfacce diverse di rete sulla base di multicast / UDP. L'utente può selezionare una scheda di rete, l'applicazione crea prese, li lega a questa scheda di rete e li aggiunge al gruppo specifico multicast.

L'invio di messaggi multicast funziona bene. Tuttavia la ricezione di messaggi riesce solo se si legano le prese ad una specifica scheda di rete del mio PC. Sembra quasi quanto v'è un 'default' NIC per la ricezione di messaggi multicast in Windows, che è sempre il primo NIC restituito dalla GetAdapterInfo la funzione.

I monitorato la rete con Wireshark e ha scoperto che il messaggio "IGMP Iscriviti al gruppo" non viene inviato dalla scheda di rete ho legato la presa in, ma da questo 'default' NIC.

Se rendo invalido questa scheda di rete (o rimuovere il cavo di rete), il prossimo NIC della lista restituita da GetAdapterInfo viene utilizzato per la ricezione dei messaggi multicast.

I era riuscito a cambiare questo 'default' NIC con l'aggiunta di una voce aggiuntiva alla tabella di routing del mio PC, ma non credo che questa è una soluzione buona del problema.

Il problema si verifica anche con il codice aggiunto sotto. Il join messaggi di gruppo non vengono inviati via 192.168.52 ma tramite una scheda di rete diversa.

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

Grazie a quattro il vostro aiuto!

È stato utile?

Soluzione

Il problema era un semplice errore di battitura. Invece di utilizzare la struttura di struct ip_mreq_source , la struttura di struct ip_mreq deve essere utilizzato se si utilizza l'opzione IP_MULTICAST_IF. (È necessaria l'altra struttura per l'opzione IP_ADD_SOURCE_MEMBERSHIP)

Usando la struttura sbagliata ha avuto la meglio, probabilmente il risultato che la funzione setsockeopt trovato uno zero in cui era previsto l'indirizzo IP NIC. Zero è anche il valore della costante INADDR_ANY, che scegliere la scheda di rete di default del sistema. : -)

Altri suggerimenti

Si consiglia di controllare / modificare la tabella di routing. Ci sarà un percorso per il traffico multicast (224.0.0.0, sottorete 240.0.0.0) in là con la sua appropriata metrica:

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

******
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top