2009-03-02 10 views

Respuesta

-1

El tráfico de multidifusión no es diferente al UDP normal a excepción de la dirección IP. Eche un vistazo a la norma socket library. Es posible que pueda encontrar algo que se base en el zócalo y que sea más fácil de usar.

+0

Derecha. ¿Pero qué hay de unirse a un grupo? Me gustaría no rodar mi propia gestión de unión de grupo si es posible. –

+7

El tráfico de multidifusión es muy diferente del tráfico UDP regular (unidifusión): debe unirse al grupo de multidifusión, todos los enrutadores y enrutadores involucrados deben tratar las implicaciones, TTL importa, generalmente no se enruta a través de la WAN. –

16

multidifusión emisor que transmite a un grupo de multidifusión:

#!/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() 

multidifusión receptor que lee de un grupo de multidifusión e imprime los datos hexagonales en la consola:

#!/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

Intenté esto, no funcionó. En Wireshark puedo ver la transmisión, pero no veo nada de IGMP y no recibo nada. –

+1

necesita enlazar al puerto/grupo de multidifusión no local en la dirección de multidifusión, 'sock.bind ((MCAST_GRP, MCAST_PORT))' – stefanB

+0

Este ejemplo no funciona para mí, por un motivo oscuro. El uso de socket.gethostbyname (socket.gethostname()) para seleccionar la interfaz no siempre elige la interfaz externa; de hecho, en los sistemas Debian, tiende a seleccionar la dirección de bucle invertido. Debian agrega una entrada de 127.0.1.1 en la tabla de host para el nombre de host. En su lugar, es más efectivo usar socket.INADDR_ANY, que la respuesta de clasificación más alta usa a través de la declaración 'paquete' (que es más correcto que '+'). Además, el uso de IP_MULTICAST_IF no es necesario, ya que la respuesta de mayor rango indica correctamente. –

78

Esto funciona para mí:

Recibir

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) 

Enviar

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

Se basa fuera de los ejemplos de http://wiki.python.org/moin/UdpCommunication que no funcionaba.

Mi sistema es ... Linux 2.6.31-15-generiC# 50-Ubuntu SMP Mar Nov 10 14:54:29 UTC 2009 i686 GNU/Linux Python 2.6.4

+6

Para mac os x necesita usar la opción socket.SO_REUSEPORT como alternativa al socket.SO_REUSEADDR en el ejemplo anterior, para permitir múltiples escuchas en la misma combinación de dirección de puerto multicast. – atikat

+0

Para enviar, también necesitaba "sock.bind ((, 0))" porque mi escucha de multidifusión estaba vinculada a un adaptador específico. –

+2

para multidifusión udp que necesita vincular al grupo/puerto de multidifusión, no al puerto del grupo local, 'sock.bind ((MCAST_GRP, MCAST_PORT))', su código podría o no funcionar, puede que no funcione cuando tenga múltiples nics – stefanB

2

Tenga una mirada en py-multicast. El módulo de red puede verificar si una interfaz admite multidifusión (al menos en 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 

Quizás los problemas para no ver IGMP hayan sido causados ​​por una interfaz que no admite la multidifusión?

+0

http://coobs.eu.org/py-multicast/ El enlace está roto – balki

+2

así que es :(, por ahora puedes probar esto: http://pypi.python.org/pypi/py-multicast – wroniasty

8

un mejor uso:

sock.bind((MCAST_GRP, MCAST_PORT)) 

en lugar de:

sock.bind(('', MCAST_PORT)) 

... porque si desea escuchar a varios grupos MCAST en el mismo puerto, obtendrá todos los mensajes en todas oyentes

0

La respuesta de tolomea funcionó para mí. Pirateé en socketserver.UDPServer también:

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

Para hacer que el código del cliente (de Tolomea) trabaja en Solaris que necesita para pasar el valor TTL para la opción IP_MULTICAST_TTL conector como un unsigned char. De lo contrario, obtendrá un error. Esto funcionó para mí en Solaris 10 y 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

Para unirse al grupo de multidifusión Python usa la interfaz de socket nativo del sistema operativo.Debido a la portabilidad y estabilidad del entorno de Python, muchas de las opciones de socket se envían directamente a la llamada de setsockopt de socket nativo. El modo de operación de multidifusión, como unirse y abandonar la membresía del grupo, solo se puede realizar al setsockopt.

programa básico para la recepción de paquetes IP multicast puede verse como:

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) 

En primer lugar se crea zócalo, se une y activa desencadena grupo de multidifusión unirse mediante la emisión de setsockopt. Al final, recibe paquetes para siempre.

El envío de marcos IP de multidifusión es sencillo. Si tiene una NIC única en su sistema, el envío de dichos paquetes no difiere del envío habitual de marcos UDP. Todo lo que tiene que hacer es simplemente configurar la dirección IP de destino correcta en el método sendto().

Observé que muchos ejemplos de Internet funcionan por accidente de hecho. Incluso en la documentación oficial de Python. Problema para todos ellos están utilizando struct.pack incorrectamente. Tenga en cuenta que el ejemplo típico usa 4sl como formato y no está alineado con la estructura de interfaz del socket del sistema operativo real.

Intentaré describir lo que sucede debajo del capó cuando ejercito setsockopt llame para el objeto de socket python.

Python reenvía la llamada al método setsockopt a la interfaz del socket C nativo. La documentación de socket de Linux (vea man 7 ip) presenta dos formas de estructura ip_mreqn para la opción IP_ADD_MEMBERSHIP. La forma más corta es de 8 bytes de longitud y más de 12 bytes de longitud. El ejemplo anterior genera 8 byte setsockopt llamada donde puño para bytes define multicast_group y segundo interface_ip.

Cuestiones relacionadas