2008-12-12 2 views
12

Ich versuche, Udp Multicast-Daten mit Sockets und C++ (c) zu bekommen. Ich habe einen Server mit 2 Netzwerkkarten, also muss ich Socket an spezifische Schnittstelle binden. Derzeit teste ich auf einem anderen Server, der nur eine Netzwerkkarte hat.Wie wird ein Socket für UDP Multicast mit 2 vorhandenen Netzwerkkarten eingerichtet?

Wenn ich INADDR_ANY benutze, kann ich die UDP-Daten sehen, wenn ich an bestimmte Schnittstelle binden sehe ich keine Daten. Die Funktion inet_addr schlägt nicht fehl (ich habe die Prüfung auf Rückgabewert vorerst abgebrochen).

Der Code ist unten. Auf einem Server mit einer Netzwerkkarte lautet meine IP-Adresse 10.81.128.44. Ich empfange Daten, wenn ich laufe wie: ./client 225.0.0.37 12346

Das gibt mir keine Daten: ./client 225.0.0.37 12346 10.81.128.44

Irgendwelche Vorschläge? (Hoffe, dass der Code kompiliert, ich entfernt Kommentare ...)

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

Vielen Dank im Voraus ...

Antwort

3

Ich glaube, Sie IP_MULTICAST_IF hinzufügen müssen

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)); 

Ich hoffe, das hilft.

7

Nach einigem Suchen und Testen fand ich here heraus, dass, wenn bindenden udp multicast socket wir Hafen spezifizieren und Adresse verlassen leer z. spezifizieren Sie INADDR_ANY.

KOMMENTAR::

Also folgendes

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())); 

sollte wie folgt aussehen, wenn ich den Code verstehen Sie sollten nicht die Wildcard-Adresse zu Ihrer Multicast Adresse verbindlich. Wenn Sie an die Platzhalteradresse binden, können Sie Unicast Pakete auf Ihrem Multicast-Port empfangen. Bindung an Ihre Multicast-Adresse wird dies verhindern und sicherstellen, dass Sie nur Multicast-Pakete an diesem Port erhalten.

EDIT: die auf dem oberen Kommentar basierten Code Feste, um Multicast-Adresse zu binden, wie in ‚Gruppe‘ gespeichert, INADDR_ANY Gegensatz zu nur Multicast-Pakete an Multicast-Adresse gesendet zu empfangen.

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())); 

Dies löste das Problem. Das Hinzufügen von IP_MULTICAST_IF wird nicht helfen, denn das ist für die Auswahl bestimmter Schnittstelle zum Senden von UDP-Daten, das oben genannte Problem war auf der Empfängerseite.

+0

Wenn ich Ihren Code verstehe, sollten Sie für Ihre Multicast-Adresse, nicht die Platzhalteradresse verbindlich sein. Wenn Sie an die Platzhalteradresse binden, können Sie Unicast-Pakete auf Ihrem Multicast-Port empfangen. Die Bindung an Ihre Multicast-Adresse verhindert dies und stellt sicher, dass Sie nur Multicast-Pakete an diesem Port erhalten. –

+0

Ihr Recht, ich habe das vor einer Weile tatsächlich herausgefunden, nur die Antwort hier nicht aktualisiert. Danke, ich habe den Code aktualisiert. – stefanB