Comment envoyer et recevoir des données UDP Multicast en Python? Existe-t-il une bibliothèque standard pour le faire?Multicast en Python
Répondre
Le trafic multicast n'est pas différent de l'UDP normal, sauf pour l'adresse IP. Jetez un oeil à la norme socket library. Vous pourriez être en mesure de trouver quelque chose qui s'appuie sur socket et est plus facile à utiliser.
émetteur Multicast qui diffuse à un groupe de multidiffusion:
#!/usr/bin/env python
import socket
import struct
def main():
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
sock.sendto('Hello World!', (MCAST_GRP, MCAST_PORT))
if __name__ == '__main__':
main()
récepteur Multicast qui lit un groupe de multidiffusion et imprime des données hexagonaux sur la console:
#!/usr/bin/env python
import socket
import binascii
def main():
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except AttributeError:
pass
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
sock.bind((MCAST_GRP, MCAST_PORT))
host = socket.gethostbyname(socket.gethostname())
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(host))
sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(MCAST_GRP) + socket.inet_aton(host))
while 1:
try:
data, addr = sock.recvfrom(1024)
except socket.error, e:
print 'Expection'
hexdata = binascii.hexlify(data)
print 'Data = %s' % hexdata
if __name__ == '__main__':
main()
J'ai essayé ça, ça n'a pas marché. Dans Wireshark, je peux voir la transmission, mais je ne vois pas de jointure IGMP et je ne reçois rien. –
vous devez vous connecter au port de multidiffusion/port non local sur l'adresse de multidiffusion, 'sock.bind ((MCAST_GRP, MCAST_PORT))' – stefanB
Cet exemple ne fonctionne pas pour moi, pour une raison obscure. L'utilisation de socket.gethostbyname (socket.gethostname()) pour sélectionner l'interface n'élit pas toujours l'interface externe - en fait, sur les systèmes debian, elle tend à sélectionner l'adresse de bouclage. Debian ajoute une entrée de 127.0.1.1 dans la table hôte pour le nom d'hôte. Au lieu de cela, il est plus efficace d'utiliser socket.INADDR_ANY, que la réponse de plus haut niveau utilise via l'instruction 'pack' (ce qui est plus correct que le '+'). En outre, l'utilisation de IP_MULTICAST_IF n'est pas requise, comme l'indique correctement la réponse de niveau supérieur. –
Cela fonctionne pour moi:
Recevoir
import socket
import struct
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', MCAST_PORT)) # use MCAST_GRP instead of '' to listen only
# to MCAST_GRP, not all groups on MCAST_PORT
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print sock.recv(10240)
Envoyer
import socket
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
sock.sendto("robot", (MCAST_GRP, MCAST_PORT))
Il est basé sur les exemples de http://wiki.python.org/moin/UdpCommunication qui ne fonctionnent pas.
Mon système est ... Linux 2.6.31-15-générique # 50 Ubuntu SMP Mar 10 novembre 14:54:29 UTC 2009 i686 GNU/Linux Python 2.6.4
Pour mac os x, vous devez utiliser l'option socket.SO_REUSEPORT comme alternative à socket.SO_REUSEADDR dans l'exemple ci-dessus, pour permettre plusieurs écouteurs sur la même combinaison d'adresses de port de multidiffusion. – atikat
Pour l'envoi, j'ai également besoin de "sock.bind ((
pour multidiffusion udp vous devez vous lier au groupe/port de multidiffusion pas au port de groupe local, 'sock.bind ((MCAST_GRP, MCAST_PORT))', votre code peut ne pas fonctionner, il peut ne pas fonctionner lorsque vous avez plusieurs nics – stefanB
Jetez un oeil au py-multicast. Le module réseau peut vérifier si une interface supporte la multidiffusion (sur Linux au moins).
import multicast
from multicast import network
receiver = multicast.MulticastUDPReceiver ("eth0", "238.0.0.1", 1234)
data = receiver.read()
receiver.close()
config = network.ifconfig()
print config['eth0'].addresses
# ['10.0.0.1']
print config['eth0'].multicast
#True - eth0 supports multicast
print config['eth0'].up
#True - eth0 is up
Peut-être des problèmes avec ne pas voir IGMP, ont été causés par une interface ne supportant pas la multidiffusion?
mieux utiliser:
sock.bind((MCAST_GRP, MCAST_PORT))
au lieu de:
sock.bind(('', MCAST_PORT))
... parce que si vous voulez écouter plusieurs groupes MCAST sur le même port, vous obtiendrez tous les messages sur tous les auditeurs
La réponse de tolomea a fonctionné pour moi. Je piraté dans socketserver.UDPServer aussi:
class ThreadedMulticastServer(socketserver.ThreadingMixIn, socketserver.UDPServer):
def __init__(self, *args):
super().__init__(*args)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
Il y a un cadre pour faire de http://twistedmatrix.com/trac/. Voici l'exemple https://twistedmatrix.com/documents/12.2.0/core/howto/udp.html
Pour rendre le code client (de Tolomea) fonctionner sous Solaris vous devez passer la valeur de l'option ttl socket IP_MULTICAST_TTL
comme un unsigned char. Sinon, vous obtiendrez une erreur. Cela a fonctionné pour moi sur Solaris 10 et 11:
import socket
import struct
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
ttl = struct.pack('B', 2)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
sock.sendto("robot", (MCAST_GRP, MCAST_PORT))
Un bon exemple qui fonctionne pour moi:
http://svn.python.org/projects/stackless/trunk/Demo/sockets/mcast.py
Pour Rejoindre le groupe de multidiffusion Python utilise l'interface socket OS natif.En raison de la portabilité et de la stabilité de l'environnement Python, de nombreuses options de socket sont directement transmises à l'appel setsockopt du socket natif. Le mode de fonctionnement multidiffusion, tel que l'appartenance à un groupe et l'abandon de groupe, peut être accompli par setsockopt
uniquement.
programme de base pour recevoir paquets IP de multidiffusion peut ressembler à:
from socket import *
multicast_port = 55555
multicast_group = "224.1.1.1"
interface_ip = "10.11.1.43"
s = socket(AF_INET, SOCK_DGRAM)
s.bind(("", multicast_port))
mreq = inet_aton(multicast_group) + inet_aton(interface_ip)
s.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, str(mreq))
while 1:
print s.recv(1500)
Tout d'abord, il crée socket, lie et déclenche déclenche le groupe de multidiffusion se joindre en émettant setsockopt
. À la toute fin, il reçoit des paquets pour toujours.
L'envoi de trames IP multicast est direct. Si vous avez une seule carte réseau dans votre système, l'envoi de ces paquets ne diffère pas de l'envoi habituel des trames UDP. Tout ce dont vous avez besoin est de régler l'adresse IP de destination correcte dans la méthode sendto()
.
J'ai remarqué que beaucoup d'exemples autour d'Internet fonctionnent en fait par accident. Même sur la documentation officielle de Python. Problème pour tous d'utiliser incorrectement struct.pack. Veuillez noter qu'un exemple typique utilise le format 4sl
et qu'il n'est pas aligné avec la structure d'interface de socket du système d'exploitation.
Je vais essayer de décrire ce qui se passe sous le capot lors de l'exercice setsockopt pour l'objet socket python.
Python transmet l'appel de la méthode setsockopt à l'interface de socket C native. La documentation de socket Linux (voir man 7 ip
) introduit deux formes de structure ip_mreqn
pour l'option IP_ADD_MEMBERSHIP. Le format le plus court est de 8 octets et le plus long de 12 octets. L'exemple ci-dessus génère 8 octets setsockopt
appel où poing pour octets définit multicast_group
et deuxième interface_ip
.
Droite. Mais que diriez-vous de rejoindre un groupe? Je ne souhaite pas lancer ma propre gestion de groupe, si possible. –
Le trafic multidiffusion est différent du trafic UDP normal (unicast): vous devez rejoindre le groupe de multidiffusion, tous les commutateurs et routeurs concernés doivent gérer les implications, la TTL est importante et n'est généralement pas acheminée via le WAN. –