Multidifusión¶
Las conexiones punto a punto manejan muchas necesidades de comunicación, pero pasar la misma información entre muchos compañeros se convierte en un desafío a medida que el número de conexiones directas crece. Enviar mensajes por separado a cada destinatario consume tiempo de procesamiento y ancho de banda adicional, que puede ser un problema para aplicaciones como la transmisión de vídeo o audio. Usar multidifusión para entregar mensajes a más de un punto final a la vez logra una mejor eficiencia porque la infraestructura de red asegura que los paquetes se entreguen a todos destinatarios.
Los mensajes de multidifusión siempre se envían utilizando UDP, ya que TCP asume un par de sistemas de comunicación. Las direcciones para multidifusión llamadas grupos de multidifusión, son un subconjunto del rango de direcciones IPv4 regulares (224.0.0.0 hasta 230.255.255.255) reservado para el tráfico multidifusión. Estas direcciones son tratadas especialmente por enrutadores y conmutadores de red, para que los mensajes enviados al grupo se puedan distribuir a través de Internet a todos los destinatarios que se han unido al grupo.
Nota
Algunos conmutadores y enrutadores administrados tienen el tráfico de multidifusión desactivado por defecto. Si tienes problemas con los programas de ejemplo, consulta la configuración de tu hardware de red.
Enviar mensajes de multidifusión¶
Este cliente de eco modificado enviará un mensaje a un grupo de multidifusión, luego informa todas las respuestas que recibe. Como no tiene forma de saber cuántas respuestas esperar, usa un valor de tiempo de espera en el conector para evitar el bloqueo indefinido mientras se espera una respuesta.
El conector también debe configurarse con un valor de tiempo de vida (TTL) para
los mensajes. El TTL controla cuántas redes recibirán el paquete. Establece
el TTL con la opción IP_MULTICAST_TTL
y setsockopt()
. El valor
predeterminado, 1
, significa que los paquetes no son reenviados por el
enrutador más allá del segmento de red actual. El valor puede variar hasta
255, y debe estar empaquetado en un byte único
import socket
import struct
import sys
message = b'very important data'
multicast_group = ('224.3.29.71', 10000)
# Create the datagram socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Set a timeout so the socket does not block
# indefinitely when trying to receive data.
sock.settimeout(0.2)
# Set the time-to-live for messages to 1 so they do not
# go past the local network segment.
ttl = struct.pack('b', 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
try:
# Send data to the multicast group
print('sending {!r}'.format(message))
sent = sock.sendto(message, multicast_group)
# Look for responses from all recipients
while True:
print('waiting to receive')
try:
data, server = sock.recvfrom(16)
except socket.timeout:
print('timed out, no more responses')
break
else:
print('received {!r} from {}'.format(
data, server))
finally:
print('closing socket')
sock.close()
El resto del remitente se parece al cliente de eco UDP, excepto que espera
respuestas múltiples, así que usa un bucle para llamar a recvfrom()
hasta
que se agote el tiempo.
Recibir de mensajes de multidifusión¶
El primer paso para establecer un receptor de multidifusión es crear el conector
UDP. Después de crear el conector normal y enlazarlo a un puerto, se puede
agregar al grupo de multidifusión usando setsockopt()
para cambiar la
opción IP_ADD_MEMBERSHIP
. El valor de opción es el representación
empaquetada de 8 bytes de la dirección del grupo de multidifusión seguida por
la interfaz de red en la que el servidor debe escuchar el tráfico, identificado
por su dirección IP. En este caso, el receptor escucha en todas las interfaces
usando INADDR_ANY
.
import socket
import struct
import sys
multicast_group = '224.3.29.71'
server_address = ('', 10000)
# Create the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Bind to the server address
sock.bind(server_address)
# Tell the operating system to add the socket to
# the multicast group on all interfaces.
group = socket.inet_aton(multicast_group)
mreq = struct.pack('4sL', group, socket.INADDR_ANY)
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
mreq)
# Receive/respond loop
while True:
print('\nwaiting to receive message')
data, address = sock.recvfrom(1024)
print('received {} bytes from {}'.format(
len(data), address))
print(data)
print('sending acknowledgement to', address)
sock.sendto(b'ack', address)
El bucle principal para el receptor es igual que el servidor eco UDP regular.
Salida ejemplo¶
Este ejemplo muestra el receptor de multidifusión ejecutándose en dos hosts.
A
tiene la dirección 192.168.1.13
y B
tiene la dirección
192.168.1.14
.
[A]$ python3 socket_multicast_receiver.py
waiting to receive message
received 19 bytes from ('192.168.1.14', 62650)
b'very important data'
sending acknowledgement to ('192.168.1.14', 62650)
waiting to receive message
[B]$ python3 source/socket/socket_multicast_receiver.py
waiting to receive message
received 19 bytes from ('192.168.1.14', 64288)
b'very important data'
sending acknowledgement to ('192.168.1.14', 64288)
waiting to receive message
El remitente se está ejecutando en el host B
.
[B]$ python3 socket_multicast_sender.py
sending b'very important data'
waiting to receive
received b'ack' from ('192.168.1.14', 10000)
waiting to receive
received b'ack' from ('192.168.1.13', 10000)
waiting to receive
timed out, no more responses
closing socket
El mensaje se envía una vez, y dos acuses de recibo de los mensajes salientes
se reciben mensajes, uno de cada host A
y B
.
Ver también
- Wikipedia: Multidifusión – Artículo que describe los detalles técnicos de la multidifusión.
- Wikipedia: Multidifusión IP – Artículo sobre IP multicasting, con información sobre direccionamiento.