92 votes

Que signifie lier un socket multicast (UDP) ?

J'utilise la multidiffusion UDP entre des hôtes qui ont plusieurs interfaces réseau. J'utilise boost::asio, et je suis confus par les 2 opérations que les récepteurs doivent effectuer : bind, puis join-group.

Pourquoi devez-vous spécifier l'adresse locale d'une interface, pendant la liaison, alors que vous le faites avec chaque groupe multicast que vous rejoignez ?

La question sœur concerne le port multicast : Puisque lors de l'envoi, on envoie vers une adresse & un port multicast, pourquoi, lors de l'abonnement à un groupe multicast, on ne spécifie que l'adresse, pas le port - le port étant spécifié lors de l'appel déroutant pour se lier.

Note : le "join-group" est une enveloppe au-dessus de la fonction setsockopt(IP_ADD_MEMBERSHIP) qui, comme documenté, peut être appelé plusieurs fois sur la même socket pour s'abonner à différents groupes (sur différents réseaux ?). Il serait donc parfaitement logique d'abandonner l'appel bind et de spécifier le port chaque fois que je m'abonne à un groupe.

D'après ce que je vois, la liaison permanente à "0.0.0.0" et la spécification de l'adresse de l'interface lors de l'adhésion au groupe fonctionnent très bien. Je suis confus.

77voto

haelix Points 567

Lier une socket UDP lors de la réception de multicast signifie spécifier une adresse et un port à partir desquels recevoir des données (PAS une interface locale, comme c'est le cas pour le bind TCP acceptor). L'adresse spécifiée dans ce cas a un filtrage c'est-à-dire que la socket ne recevra que les datagrammes envoyés à cette adresse et à ce port multicast, quels que soient les groupes auxquels la socket se joindra par la suite. Cela explique pourquoi, en me liant à INADDR_ANY (0.0.0.0), j'ai reçu des datagrammes envoyés à mon groupe multicast, alors qu'en me liant à l'une des interfaces locales, je n'ai rien reçu, même si les datagrammes étaient envoyés sur le réseau auquel cette interface correspondait.

Citation de UNIX® Network Programming Volume 1, Third Edition : The Sockets Networking API par W.R Stevens. 21.10. Envoi et réception

[...] Nous voulons que le socket récepteur lie le groupe multicast et port, disons 239.255.1.2 port 8888. (Rappelez-vous que nous pourrions simplement lier la l'adresse IP et le port 8888, mais lier l'adresse multicast empêche la socket de recevoir empêche la socket de recevoir d'autres datagrammes qui pourraient arriver à destination du port 8888). Nous voulons ensuite que la socket réceptrice rejoigne le groupe multicast. La socket d'envoi enverra des datagrammes à cette même adresse et ce même port multicast, disons 239.255.1.2 port 8888.

0 votes

Faites cette expérience : dans la même application - créez 2 sockets, joignez chacun à un groupe différent. Envoyez du trafic aux deux groupes (sur des numéros de port identiques !) - Si vous ne définissez pas l'adresse lors de la liaison, vous obtiendrez du trafic pour les deux groupes, je pense ...

1 votes

@nhed : Sous Linux, il n'est même pas nécessaire qu'il soit dans le même processus. En vous liant à 0.0.0.0, vous recevrez tout le trafic multicast vers ce port pour lequel vous et d'autres processus sur l'hôte avez ajouté une adhésion de groupe.

0 votes

@JohannesOvermann, d'accord. Je proposais juste un test simple pour montrer que l'assertion de l'OP always binding to "0.0.0.0" and specifying the interface address when joining the group, works very well c'est faux

67voto

selbie Points 20267

L'opération "bind" revient à dire "utilisez ce port UDP local pour envoyer et recevoir des données". En d'autres termes, elle alloue ce port UDP à l'usage exclusif de votre application. (Il en va de même pour les sockets TCP).

Lorsque vous vous liez à "0.0.0.0" ( INADDR_ANY ), vous demandez à la couche TCP/IP d'utiliser tous les adaptateurs disponibles pour écouter et de choisir le meilleur adaptateur pour envoyer. C'est une pratique standard pour la plupart des codes de socket. La seule fois où vous ne spécifiez pas 0 pour l'adresse IP est lorsque vous voulez envoyer/recevoir sur une carte réseau spécifique.

De même, si vous spécifiez une valeur de port de 0 pendant la liaison, le système d'exploitation attribuera un numéro de port disponible aléatoirement pour ce socket. Ainsi, pour le multicast UDP, vous devez vous lier à INADDR_ANY sur un numéro de port spécifique vers lequel le trafic multicast doit être envoyé.

L'opération "joindre un groupe multicast" ( IP_ADD_MEMBERSHIP ) est nécessaire car il indique à votre carte réseau d'écouter non seulement les trames Ethernet dont l'adresse MAC de destination est la vôtre, mais il indique également à la carte Ethernet ( NIC ) pour écouter le trafic multicast IP ainsi que l'adresse ethernet multicast correspondante. Chaque IP multicast correspond à une adresse ethernet multicast. Lorsque vous utilisez un socket pour envoyer des données à une IP de multidiffusion spécifique, l'adresse MAC de destination de la trame Ethernet est définie comme l'adresse MAC de multidiffusion correspondante pour l'IP de multidiffusion. Lorsque vous rejoignez un groupe de multidiffusion, vous configurez la carte réseau pour qu'elle écoute le trafic envoyé à cette même adresse MAC (en plus de la sienne).

Sans le support matériel, la multidiffusion ne serait pas plus efficace que la simple diffusion de messages IP. L'opération jointe indique également à votre routeur/ passerelle de transférer le trafic multicast d'autres réseaux. (Quelqu'un se souvient de MBONE ?)

Si vous rejoignez un groupe de multidiffusion, tout le trafic de multidiffusion pour tous les ports de cette adresse IP sera reçu par la NIC. Seul le trafic destiné à votre port d'écoute lié sera transmis à votre application par la pile TCP/IP. En ce qui concerne la raison pour laquelle les ports sont spécifiés lors d'une souscription multicast - c'est parce que l'IP multicast est juste cela - IP seulement. Les "ports" sont une propriété des protocoles supérieurs (UDP et TCP).

Vous pouvez en savoir plus sur la manière dont les adresses IP de multidiffusion correspondent aux adresses Ethernet de multidiffusion sur différents sites. L'article de Wikipedia est aussi bon que possible :

L'IANA possède l'adresse MAC OUI 01:00:5e, par conséquent les paquets multicast sont délivrés en utilisant la plage d'adresses MAC Ethernet 01:00:5e:00:00:00 - 01:00:5e:7f:ff:ff. Cela représente 23 bits d'espace d'adressage espace d'adressage disponible. Le premier octet (01) comprend le bit de diffusion/multicast de diffusion. Les 23 bits inférieurs de l'adresse IP multidiffusion de 28 bits sont mappés. dans les 23 bits de l'espace d'adresse Ethernet disponible.

1 votes

Merci de votre intérêt, Selbie. L'utilisation de bind(0.0.0.0) est donc pertinente car elle spécifie l'interface sur laquelle recevoir les messages entrants. unicast Paquets UDP ? J'ai essayé des paramètres autres que 0.0.0.0 lors de la liaison, mais rien ne fonctionne (pas même l'interface spécifique au réseau sur lequel le trafic multicast est envoyé). Je ne comprends toujours pas la signification de l'adresse bind().

0 votes

Petite note, pour TCP, il est très clair ce que bind(interfAddr, port) fait. Il n'accepte les connexions que depuis ce réseau spécifique, j'ai vérifié que c'était correct. Mais pour les sockets UDP, l'adresse de liaison semble redondante avec le second argument de IP_ADD_MEMBERSHIP. Ce n'est pas exactement redondant, puisque le paramétrage de cette adresse ne semble pas fonctionner - seul 0.0.0.0 fonctionne.

0 votes

Je ne suis pas sûr de ce que vous voulez dire par "rien ne fonctionne". Postez un code démontrant le problème. En ce qui concerne la question de la redondance, je suppose que vous pourriez vous lier à tous les adaptateurs (INADDR_ANY == 0.0.0.0) et ensuite effectuer un enregistrement multicast sur une interface spécifique. Je pense qu'ils voulaient simplement que l'interface soit flexible. Lisez la section 6.4 de ce lien. tldp.org/HOWTO/Multicast-HOWTO-6.html sur une discussion similaire sur la raison pour laquelle l'interface doit être transmise.

13voto

Yury Schkatula Points 833

Correction pour Que signifie lier une socket multicast (udp) ? pour autant qu'il soit partiellement vrai à la citation suivante :

L'opération "bind" revient à dire "utilisez ce port UDP local pour envoyer et recevoir des données". En d'autres termes, elle alloue ce port UDP pour l'envoi et la réception de données. exclusif utilisation pour votre application

Il y a une exception. Applications multiples peut partagent le même port pour l'écoute (cela a généralement une valeur pratique pour les datagrammes multicast), si les SO_REUSEADDR option appliquée. Par exemple

int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // create UDP socket somehow
...
int set_option_on = 1;
// it is important to do "reuse address" before bind, not after
int res = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &set_option_on, 
    sizeof(set_option_on));
res = bind(sock, src_addr, len);

Si plusieurs processus ont effectué une telle "liaison de réutilisation", alors chaque datagramme UDP reçu sur ce port partagé sera livré à chacun des processus (ce qui fournit une articulation naturelle avec le trafic multicast).

Voici des détails supplémentaires concernant ce qui se passe dans quelques cas :

  1. toute tentative de liaison ("exclusive" ou "réutilisation") avec le port libre sera réussie.

  2. la tentative de "liaison exclusive" échouera si le port est déjà "lié par réutilisation".

  3. La tentative de "réutilisation de la liaison" échouera si un processus conserve la "liaison exclusive".

9voto

Keith Knauber Points 44

Il est également très important de distinguer une socket multicast émettrice d'une socket multicast réceptrice.

Je suis d'accord avec toutes les réponses ci-dessus concernant la RÉCEPTION des sockets multicast. Le PO a noté que lier une socket RECEIVING à une interface n'a pas aidé. Cependant, il est nécessaire de lier une socket multicast SENDING à une interface.

Pour une socket multicast SENDING sur un serveur multi-homed, c'est très Il est important de créer une socket séparée pour chaque interface à laquelle vous voulez envoyer des données. Une socket SENDING liée doit être créée pour chaque interface.

  // This is a fix for that bug that causes Servers to pop offline/online.
  // Servers will intermittently pop offline/online for 10 seconds or so.
  // The bug only happens if the machine had a DHCP gateway, and the gateway is no longer accessible.
  // After several minutes, the route to the DHCP gateway may timeout, at which
  // point the pingponging stops.
  // You need 3 machines, Client machine, server A, and server B
  // Client has both ethernets connected, and both ethernets receiving CITP pings (machine A pinging to en0, machine B pinging to en1)
  // Now turn off the ping from machine B (en1), but leave the network connected.
  // You will notice that the machine transmitting on the interface with
  // the DHCP gateway will fail sendto() with errno 'No route to host'
  if ( theErr == 0 )
  {
     // inspired by 'ping -b' option in man page:      
     //      -b boundif
     //             Bind the socket to interface boundif for sending.
     struct sockaddr_in bindInterfaceAddr;
     bzero(&bindInterfaceAddr, sizeof(bindInterfaceAddr));
     bindInterfaceAddr.sin_len = sizeof(bindInterfaceAddr);
     bindInterfaceAddr.sin_family = AF_INET;
     bindInterfaceAddr.sin_addr.s_addr = htonl(interfaceipaddr);
     bindInterfaceAddr.sin_port = 0; // Allow the kernel to choose a random port number by passing in 0 for the port.
     theErr = bind(mSendSocketID, (struct sockaddr *)&bindInterfaceAddr, sizeof(bindInterfaceAddr));
     struct sockaddr_in serverAddress;
     int namelen = sizeof(serverAddress);  
     if (getsockname(mSendSocketID, (struct sockaddr *)&serverAddress, (socklen_t *)&namelen) < 0) {
        DLogErr(@"ERROR Publishing service... getsockname err");
     }
     else
     {
        DLog( @"socket %d bind, %@ port %d", mSendSocketID, [NSString stringFromIPAddress:htonl(serverAddress.sin_addr.s_addr)], htons(serverAddress.sin_port) );
     }

Sans ce correctif, l'envoi de multicast obtiendra par intermittence sendto() errno 'No route to host'. Si quelqu'un peut m'éclairer sur la raison pour laquelle le débranchement d'une passerelle DHCP provoque la confusion des sockets d'envoi de multidiffusion de Mac OS X, j'aimerais l'entendre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X