2009-03-02 16 views

risposta

-1

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.

+0

Diritto. Ma che ne dici di entrare in un gruppo? Mi piacerebbe non aprire il mio gruppo di gestione del gruppo, se possibile. –

+7

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. –

16

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() 
+0

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. –

+1

è necessario eseguire il binding alla porta multicast di gruppo/porta non locale sull'indirizzo multicast, 'sock.bind ((MCAST_GRP, MCAST_PORT))' – stefanB

+0

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. –

78

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

+6

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

+0

Per l'invio, avevo anche bisogno di "sock.bind ((, 0))" perché il listener multicast era associato a un adattatore specifico. –

+2

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

2

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?

+0

http://coobs.eu.org/py-multicast/ link is broken – balki

+2

così è :(, per ora puoi provare questo: http://pypi.python.org/pypi/py-multicast – wroniasty

8

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

0

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

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

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.

Problemi correlati