Question

Je développe avec plusieurs interfaces réseau un outil de diagnostic sur un PC basé sur la multidiffusion / udp. L'utilisateur peut sélectionner une carte réseau, l'application crée les sockets, les lie à cette carte réseau et les ajoute au groupe de multidiffusion spécifique.

L'envoi de messages de multidiffusion fonctionne très bien. Cependant la réception de messages ne réussit que si je lie les prises à une carte réseau spécifique de mon PC. Il ressemble presque comme il y a une carte réseau « par défaut » pour recevoir des messages de multidiffusion dans Windows qui est toujours la première carte réseau retournée par le GetAdapterInfo fonction.

J'ai suivi le réseau avec Wireshark et a découvert que le message « IGMP Rejoindre le groupe » n'est pas envoyé de la carte réseau I lié à la prise, mais ce « défaut » NIC.

Si je désactive cette carte réseau (ou supprimer le câble réseau), la prochaine carte réseau de la liste renvoyée par GetAdapterInfo est utilisé pour recevoir des messages de multidiffusion.

J'a réussi à changer cette carte réseau « par défaut » en ajoutant une entrée supplémentaire à la table de routage de mon PC, mais je ne pense pas que ce soit une bonne solution du problème.

Le problème se produit également avec le code en annexe ci-dessous. La jointure des messages de groupe ne sont pas envoyés par 192.168.52 mais via une carte réseau différente.

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

Merci quatre votre aide!

Était-ce utile?

La solution

Le problème était une typo simple. Au lieu d'utiliser la structure struct ip_mreq_source , la structure struct ip_mreq doit être utilisé si vous utilisez l'option IP_MULTICAST_IF. (L'autre structure est nécessaire pour l'option IP_ADD_SOURCE_MEMBERSHIP)

En utilisant la mauvaise structure devait très probablement le résultat que la fonction setsockeopt trouve un zéro où l'adresse IP NIC était attendue. Zero est également la valeur de la constante INADDR_ANY, qui choisissent la carte réseau par défaut du système. : -)

Autres conseils

Vous pouvez vérifier / modifier votre table de routage. Il y aura une route pour la multidiffusion (224.0.0.0, sous-réseau 240.0.0.0) le trafic là-bas avec sa métrique appropriée:

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

******
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top