This repository was archived by the owner on Nov 23, 2017. It is now read-only.
This repository was archived by the owner on Nov 23, 2017. It is now read-only.
Can't receive replies to multicast UDP packets #480
Open
Description
It doesn't appear to be possible to receive replies to multicast UDP messages. Server-side multicast does work, but only with a bit of extra config.
Given the following (working) server code, adapted from the UDP Echo example:
import asyncio
import logging
import socket
import struct
BROADCAST_PORT = 1910
BROADCAST_ADDR = "239.255.255.250"
class MulticastServerProtocol:
def connection_made(self, transport):
self.transport = transport
def datagram_received(self, data, addr):
print('Received {!r} from {!r}'.format(data, addr))
data = "I received {!r}".format(data).encode("ascii")
print('Send {!r} to {!r}'.format(data, addr))
self.transport.sendto(data, addr)
loop = asyncio.get_event_loop()
loop.set_debug(True)
logging.basicConfig(level=logging.DEBUG)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', BROADCAST_PORT))
group = socket.inet_aton(BROADCAST_ADDR)
mreq = struct.pack('4sL', group, socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
listen = loop.create_datagram_endpoint(
MulticastServerProtocol,
sock=sock,
)
transport, protocol = loop.run_until_complete(listen)
loop.run_forever()
loop.close()
...the following non-asyncio client code sends a broadcast packet and correctly receives the responses:
import socket
import struct
import sys
BROADCAST_PORT = 1910
BROADCAST_ADDR = "239.255.255.250"
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(3)
ttl = struct.pack('b', 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
try:
sent = sock.sendto(
sys.argv[1].encode("ascii"),
(BROADCAST_ADDR, BROADCAST_PORT)
)
while True:
try:
data, server = sock.recvfrom(1024)
except socket.timeout:
break
else:
print("Reply from {}: {!r}".format(server, data))
finally:
sock.close()
However, the following code, which I'm pretty sure is the asyncio equivalent, sends out the mutlicast packet correctly but never receives a response:
import asyncio
import socket
import struct
import sys
BROADCAST_PORT = 1910
BROADCAST_ADDR = "239.255.255.250"
class DiscoveryClientProtocol:
def __init__(self, loop):
self.loop = loop
self.transport = None
def connection_made(self, transport):
self.transport = transport
sock = self.transport.get_extra_info('socket')
sock.settimeout(3)
ttl = struct.pack('b', 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
self.transport.sendto(sys.argv[1].encode("ascii"))
def datagram_received(self, data, addr):
print("Reply from {}: {!r}".format(addr, data))
# Don't close the socket as we might get multiple responses.
def error_received(self, exc):
print('Error received:', exc)
def connection_lost(self, exc):
print("Socket closed, stop the event loop")
self.loop.stop()
loop = asyncio.get_event_loop()
connect = loop.create_datagram_endpoint(
lambda: DiscoveryClientProtocol(loop),
remote_addr=(BROADCAST_ADDR, BROADCAST_PORT),
)
transport, protocol = loop.run_until_complete(connect)
loop.run_forever()
transport.close()
loop.close()
Metadata
Metadata
Assignees
Labels
No labels