Bill Bill - 2 months ago 17
Python Question

Python recv multicast returns one byte

recv is not working as expected.
I am sending 10 bytes (verified with wireshark) and recv is only getting the first byte and discarding the rest (until the next sendto).
Is this a multicast thing? I'm pretty sure I've done this same thing with unicast UDP and had no issues.

Here is my example code:

import struct, socket, multiprocessing, time

MCAST_PORT = 62950
MCAST_GRP = '239.0.0.13'

def _Rx(self, RXsock, Queue):
print "Receiver started"
while True:
# State machine goes here to parse header and recv (<msglen>) bytes.
print "Waiting Rx char...", RXsock
char = RXsock.recv(1) # Blocks here after first byte ("1") ???
print "Rx", hex(ord(char))



TXsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
TXsock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)

RXsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
RXsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
RXsock.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
RXsock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

RxQueue = multiprocessing.Queue()
receiver = multiprocessing.Process(target=_Rx, args=(None, RXsock, RxQueue))
receiver.daemon = True
receiver.start()


TXsock.sendto("09123456789", (MCAST_GRP, MCAST_PORT))
time.sleep(3)

Answer

You are only getting one byte because you set your buffer size to one.

From the documentation for socket.recv:

The maximum amount of data to be received at once is specified by bufsize.

Try passing 1024 or 4096 to recv.

From the man page for recv:

If a message is too long to fit in the supplied buffer, excess bytes may be discarded depending on the type of socket the message is received from.

Your comment says that you are trying to parse the header one byte at a time. You can always parse the header after you finish receiving the datagram.

If you really need to do a partial read of the buffer, try passing the socket.MSG_PEEK flag to recv:

MSG_PEEK

This flag causes the receive operation to return data from the beginning of the receive queue without removing that data from the queue. Thus, a subsequent receive call will return the same data.

However, you still won't be able to read one byte at a time.