2008-12-12 6 views
12

J'essaie d'obtenir des données multidiffusion udp en utilisant des sockets et C++ (c). J'ai un serveur avec 2 cartes réseau donc j'ai besoin de relier le socket à une interface spécifique. Actuellement, je suis en train de tester sur un autre serveur qui n'a qu'une seule carte réseau. Lorsque j'utilise INADDR_ANY, je peux voir les données udp, quand je me lie à une interface spécifique, je ne vois aucune donnée. La fonction inet_addr n'échoue pas (j'ai enlevé la vérification de la valeur de retour pour le moment).Comment configurer un socket pour la multidiffusion UDP avec 2 cartes réseau présentes?

Le code est ci-dessous. Sur un serveur avec une carte réseau, mon adresse IP est 10.81.128.44. Je reçois des données quand je cours comme: ./client 225.0.0.37 12346

Cela me donne aucune donnée: ./client 225.0.0.37 12346 10.81.128.44

Toutes les suggestions? (Espérons que le code compile, j'ai supprimé les commentaires ...)

#include <stdlib.h> 
    #include <sys/types.h> 
    #include <sys/socket.h> 
    #include <netinet/in.h> 
    #include <arpa/inet.h> 
    #include <time.h> 
    #include <string.h> 
    #include <stdio.h> 

    #include <iostream> 
    #include <string> 

    using namespace std; 

    #define HELLO_PORT 12345 
    #define HELLO_GROUP "225.0.0.37" 
    #define MSGBUFSIZE 256 

    int main(int argc, char *argv[]) 
    { 
     string source_iface; 
     string group(HELLO_GROUP); 
     int port(HELLO_PORT); 

     if (!(argc < 2)) group = argv[1]; 
     if (!(argc < 3)) port = atoi(argv[2]); 
     if (!(argc < 4)) source_iface = argv[3]; 

     cout << "group: " << group << " port: " << port << " source_iface: " << source_iface << endl; 

     int fd; 
     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
     { 
      perror("socket"); 
      exit(1); 
     } 

     u_int yes = 1; 
     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) 
     { 
      perror("Reusing ADDR failed"); 
      exit(1); 
     } 

     struct sockaddr_in addr; 
     memset(&addr, 0, sizeof(addr)); 
     addr.sin_family = AF_INET; 
     addr.sin_port = htons(port); 
     addr.sin_addr.s_addr = (source_iface.empty() ? htonl(INADDR_ANY) : inet_addr(source_iface.c_str())); 

    if (bind(fd,(struct sockaddr *)&addr, sizeof(addr)) < 0) 
    { 
     perror("bind"); 
     exit(1); 
    } 

    struct ip_mreq mreq; 
    mreq.imr_multiaddr.s_addr = inet_addr(group.c_str()); 
    mreq.imr_interface.s_addr = (source_iface.empty() ? htonl(INADDR_ANY) : inet_addr(source_iface.c_str())); 

    if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) 
    { 
     perror("setsockopt"); 
     exit(1); 
    } 

    socklen_t addrlen; 
    int nbytes; 
    char msgbuf[MSGBUFSIZE]; 

    while (1) 
    { 
     memset(&msgbuf, 0, MSGBUFSIZE); 

     addrlen = sizeof(addr); 
     if ((nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0, (struct sockaddr *)&addr, &addrlen)) < 0) 
     { 
      perror("recvfrom"); 
      exit(1); 
     } 
     cout.write(msgbuf, nbytes); 
     cout.flush(); 
    } 

    return 0; 
} 

Merci à l'avance ...

Répondre

3

Je pense que vous devez ajouter IP_MULTICAST_IF

struct ip_mreq   multi; 

    multi.imr_multiaddr.s_addr = inet_addr(group.c_str()); 
    multi.imr_interface.s_addr = (source_iface.empty() ? 
     htonl(INADDR_ANY): inet_addr(source_iface.c_str())); 

    status = setsockopt(me->ns_fd, IPPROTO_IP, IP_MULTICAST_IF, 
     (char *)&multi.imr_interface.s_addr, 
     sizeof(multi.imr_interface.s_addr)); 

J'espère que cela aide.

7

Après quelques recherches et tests, j'ai découvert here que lorsque liaison udp multicast socket, nous spécifions le port et laissez l'adresse vide, par exemple. spécifiez INADDR_ANY.

Ainsi, les éléments suivants

addr.sin_family = AF_INET; 
addr.sin_port = htons(port); 
addr.sin_addr.s_addr = (source_iface.empty() ? 
         htonl(INADDR_ANY) : 
         inet_addr(source_iface.c_str())); 

devrait être ressembler à:

COMMENTAIRE: Si je comprends bien votre code que vous devriez liez à votre adresse de multidiffusion pas l'adresse générique. Si vous liez à l'adresse générique vous sera en mesure de recevoir unicast paquets sur votre port de multidiffusion. La liaison à votre adresse de multidiffusion empêchera cela et vous assurer que vous obtenez seulement paquets de multidiffusion sur ce port.

EDIT: Correction du code basé sur le commentaire ci-dessus, la liaison à l'adresse de multidiffusion, stocké dans « groupe », par opposition à INADDR_ANY de ne recevoir que les paquets de multidiffusion envoyés à adresse de multidiffusion.

addr.sin_family = AF_INET; 
addr.sin_port = htons(port); 
addr.sin_addr.s_addr = (group.empty() ? 
         htonl(INADDR_ANY) : 
         inet_addr(group.c_str())); 

Ce résolu le problème. Ajoutant IP_MULTICAST_IF ne va pas aider, car c'est pour la sélection d'interface spécifique pour l'envoi de données udp, le problème ci-dessus était sur le côté récepteur.

+0

Si je comprends votre code, vous devez lier votre adresse de multidiffusion pas l'adresse générique. Si vous vous connectez à l'adresse générique, vous pourrez recevoir des paquets monodiffusion sur votre port de multidiffusion. La liaison à votre adresse de multidiffusion l'empêchera et vous assurera que vous n'aurez que des paquets de multidiffusion sur ce port. –

+0

Votre droite, je l'ai trouvé il y a un certain temps, je n'ai tout simplement pas mis à jour la réponse ici. Merci, j'ai mis à jour le code. – stefanB

Questions connexes