Come si invia e riceve UDP Multicast in Python? C'è una libreria standard per farlo?Multicast in Python
risposta
Il traffico multicast non è diverso dal normale UDP tranne l'indirizzo IP. Dai uno sguardo allo standard socket library. Potresti riuscire a trovare qualcosa che si basa su socket ed è più facile da usare.
Multicast mittente che trasmette ad un gruppo multicast:
#!/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()
Multicast ricevitore che legge da un gruppo multicast e stampa dati esadecimali alla 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()
Ho provato questo, non ha funzionato. In Wireshark riesco a vedere la trasmissione, ma non vedo alcun elemento di partecipazione IGMP e non ricevo nulla. –
è necessario eseguire il binding alla porta multicast di gruppo/porta non locale sull'indirizzo multicast, 'sock.bind ((MCAST_GRP, MCAST_PORT))' – stefanB
Questo esempio non funziona per me, per un motivo oscuro. Usando socket.gethostbyname (socket.gethostname()) per selezionare l'interfaccia non sempre si sceglie l'interfaccia esterna - infatti, su sistemi debian, tende a selezionare l'indirizzo di loopback. Debian aggiunge una voce di 127.0.1.1 nella tabella host per il nome host. Invece, è più efficace utilizzare socket.INADDR_ANY, che la risposta di livello più alto utilizza attraverso l'istruzione 'pack' (che è più corretta di '+'). Inoltre, l'uso di IP_MULTICAST_IF non è richiesto, come indica correttamente la risposta di livello più alto. –
Questo funziona per me:
Ricevi
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)
Invia
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))
Si basa fuori gli esempi http://wiki.python.org/moin/UdpCommunication che non ha funzionato.
Il mio sistema è ... Linux 2.6.31-15-generiC# 50-Ubuntu SMP Mar 10 Nov 14:54:29 UTC 2009 i686 GNU/Linux Python 2.6.4
Per mac os x è necessario utilizzare l'opzione socket.SO_REUSEPORT in alternativa a socket.SO_REUSEADDR nell'esempio precedente, per consentire più listener sulla stessa combinazione di indirizzi di porta multicast. – atikat
Per l'invio, avevo anche bisogno di "sock.bind ((
per multicast di udp che è necessario associare al gruppo/porta multicast non alla porta del gruppo locale, 'sock.bind ((MCAST_GRP, MCAST_PORT))', il proprio codice potrebbe e potrebbe non funzionare, potrebbe non funzionare quando si dispone di più nics – stefanB
Date un'occhiata a py-multicast. Il modulo di rete può verificare se un'interfaccia supporta il multicast (almeno su Linux).
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
Forse problemi con il non vedere IGMP, sono stati causati da un'interfaccia che non supporta il multicast?
un uso migliore:
sock.bind((MCAST_GRP, MCAST_PORT))
invece di:
sock.bind(('', MCAST_PORT))
... perché se si desidera ascoltare più gruppi MCAST sulla stessa porta, si otterrà tutti i messaggi su tutti ascoltatori
La risposta di tolomea ha funzionato per me. Ho inciso in socketserver.UDPServer troppo:
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)
esiste un quadro per fare questo da http://twistedmatrix.com/trac/. Ecco l'esempio https://twistedmatrix.com/documents/12.2.0/core/howto/udp.html
Per rendere il codice del client (da Tolomea) lavora su Solaris è necessario passare il valore TTL per l'opzione IP_MULTICAST_TTL
presa come un unsigned char. Altrimenti si otterrà un errore. Questo ha funzionato per me su Solaris 10 e 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 buon esempio che funziona per me:
http://svn.python.org/projects/stackless/trunk/Demo/sockets/mcast.py
al fine di unire gruppo multicast Python usa nativo interfaccia socket OS.A causa della portabilità e della stabilità dell'ambiente Python, molte delle opzioni di socket vengono inoltrate direttamente alla chiamata setockopt socket nativa. La modalità di funzionamento multicast come l'adesione e l'eliminazione dell'appartenenza al gruppo può essere eseguita solo tramite setsockopt
.
programma di base per ricevere multicast pacchetto IP può assomigliare:
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)
In primo luogo crea socket, lo lega e fa scattare innesca gruppo multicast unendo mediante l'emissione di setsockopt
. Alla fine riceve pacchetti per sempre.
L'invio di frame IP multicast è semplice. Se si dispone di una singola scheda NIC nel proprio sistema, l'invio di tali pacchetti non differisce dal normale invio di frame UDP. Tutto ciò di cui hai bisogno è semplicemente impostare l'indirizzo IP di destinazione corretto nel metodo sendto()
.
Ho notato che molti esempi su Internet funzionano per errore in effetti. Anche sulla documentazione ufficiale di Python. Il problema per tutti loro sta usando struct.pack in modo errato. Si noti che l'esempio tipico utilizza come formato il formato 4sl
e non è allineato con la reale struttura dell'interfaccia socket del SO.
Cercherò di descrivere cosa succede sotto il cofano quando si esercita la chiamata setsockopt per l'oggetto python socket.
Python inoltra la chiamata del metodo setsockopt all'interfaccia socket C nativa. La documentazione del socket di Linux (vedere man 7 ip
) introduce due forme di struttura ip_mreqn
per l'opzione IP_ADD_MEMBERSHIP. La forma più corta è lunga 8 byte e lunga più di 12 byte. Sopra l'esempio genera 8 byte setsockopt
chiamata dove pugno per byte definisce multicast_group
e il secondo interface_ip
.
Diritto. Ma che ne dici di entrare in un gruppo? Mi piacerebbe non aprire il mio gruppo di gestione del gruppo, se possibile. –
Il traffico multicast è _quello_ diverso dal normale traffico UDP (unicast): è necessario unirsi al gruppo multicast, tutti gli switch ei router coinvolti devono occuparsi delle implicazioni, questioni TTL, in genere non instradate attraverso la WAN. –