python - example - udp echo server
¿Por qué se combinan los mensajes de multidifusión en el mismo puerto pero de diferentes grupos? (2)
La principal diferencia con la recepción de múltiples alimentaciones de multidifusión en el mismo puerto - C, Linux es que está utilizando Python.
En mcast_rcv
, puede habilitar el filtro de grupo deshabilitando la opción IP_MULTICAST_ALL
, permitiendo que IP_MULTICAST_ALL
este IP_MULTICAST_ALL
:
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))
mreq = struct.pack(''4sl'', socket.inet_aton(mcast_group), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# disable mc_all
if hasattr(socket,''IP_MULTICAST_ALL'') != True:
socket.IP_MULTICAST_ALL = 49
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_ALL, 0)
Como el python que utilicé no define socket.IP_MULTICAST_ALL
, podría ser necesario definirlo.
Esta pregunta ya tiene una respuesta aquí:
En un servidor Ubuntu 14.04 tengo dos procesos, cada uno escuchando mensajes de multidifusión en el mismo puerto, pero de diferentes grupos. No esperaba esto, pero cada uno ve el tráfico tanto del grupo que quieren como del otro grupo.
Por lo que puedo decir, este es un comportamiento conocido (aunque lo llamaría un problema). Encontré esta pregunta SO , que proporciona algunas técnicas para determinar el grupo de multidifusión de donde se reciben los datos, pero no responde la pregunta de por qué esto está sucediendo en primer lugar. Hubiera pensado que el código de red del sistema subyacente habría filtrado mensajes en grupos de multidifusión que no estoy intentando recibir.
Mientras estoy trabajando principalmente en C ++, puedo proporcionar un código Python simple para demostrar el problema. En una ventana de terminal escucho en el grupo de multidifusión 239.1.1.1, puerto 12345. En otra ventana de terminal en el mismo servidor escucho el grupo de multidifusión 239.2.2.2, también el puerto 12345. En una segunda máquina, transmito un mensaje de multidifusión en 239.1. 1.1: 12345, y un mensaje diferente en 239.2.2.2:12345.
En svr3, el transmisor:
rcook@svr3:~$ mcast_snd 239.1.1.1 12345 "from 1.1.1"
multicasting from 1.1.1 to 239.1.1.1 port 12345
rcook@svr3:~$ mcast_snd 239.2.2.2 12345 "from 2.2.2"
multicasting from 2.2.2 to 239.2.2.2 port 12345
En svr2, ventana 1, el primer receptor:
rcook@svr2:~$ mcast_rcv 239.1.1.1 12345
listening for multicast data on 239.1.1.1 port 12345
received 10 bytes: from 1.1.1
received 10 bytes: from 2.2.2
En svr2, terminal 2, el otro receptor:
rcook@svr2:~$ mcast_rcv 239.2.2.2 12345
listening for multicast data on 239.2.2.2 port 12345
received 10 bytes: from 1.1.1
received 10 bytes: from 2.2.2
Como puede ver, ambos receptores reciben ambos mensajes. ¿Alguien puede explicar por qué es esto? Y si hay una forma mejor de configurar los receptores para que no reciban mensajes de otros grupos, por favor, compártelo también.
Como referencia, aquí está el código para mcast_rcv:
#!/usr/bin/python
import socket
import struct
import sys
if len(sys.argv) != 3:
print ''usage:'', sys.argv[0], ''<multicast group>'', ''<multicast port>''
sys.exit(0)
mcast_group = sys.argv[1]
mcast_port = int(sys.argv[2])
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))
mreq = struct.pack(''4sl'', socket.inet_aton(mcast_group), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
print ''listening for multicast data on'', mcast_group, ''port'', mcast_port
while True:
msg = sock.recv(10240)
print ''received'', len(msg), ''bytes:'', msg
Y aquí está el código para mcast_snd:
#!/usr/bin/python
import socket
import sys
if len(sys.argv) != 4:
print ''usage:'', sys.argv[0], ''<multicast group>'', ''<multicast port>'', ''<mess
age>''
sys.exit(0)
mcast_group = sys.argv[1]
mcast_port = int(sys.argv[2])
message = sys.argv[3]
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
print ''multicasting'', message, ''to'', mcast_group, ''port'', mcast_port
sock.sendto(message, (mcast_group, mcast_port))
Problema resuelto. Necesito especificar el grupo de multidifusión para enlazar en el receptor, no solo en el puerto. Esta pregunta SO me dio seguimiento. Al dejar la dirección como ''''
en el código de Python, o INADDR_ANY
en mi C ++, básicamente le digo al sistema operativo que quiero que todos los mensajes en ese puerto, independientemente del grupo. El sistema me está dando exactamente lo que estoy pidiendo, como siempre lo hace.
Si reemplazo la línea sock.bind(('''', mcast_port))
con sock.bind((mcast_group, mcast_port))
en mcast_rcv, el comportamiento es el que espero y deseo. El mero hecho de unirse al grupo de multidifusión ( sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
) no es suficiente para filtrar los mensajes que no son de grupo en ese puerto.