Receive multicast UDP datagrams with python on Linux

江枫思渺然 提交于 2019-12-08 09:34:53

问题


I have a hardware device that sends multicast data on my network. I have written a python script that receives the data and prints it. However, I've found that it only works on my Windows XP PC and doesn't work on my Ubuntu Linux 10.04 PC. Under Linux, nothing is received. It just goes round the while loop and there's never any data received. My code is posted below. Can you see any reason why this will not work under Linux? Thanks, Rab.

# Multicast client
# Adapted from: http://chaos.weblogs.us/archives/164
# on 05/03/2013

import socket

ANY = "0.0.0.0" 
MCAST_ADDR = "224.0.33.154"
MCAST_PORT = 31800

# Create a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

# Allow multiple sockets to use the same PORT number
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

# Bind to the port that we know will receive multicast data
sock.bind((ANY,MCAST_PORT))

# Tell the kernel that we are a multicast socket
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)

# Tell the kernel that we want to add ourselves to a multicast group
# The address for the multicast group is the third param
status = sock.setsockopt(socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(MCAST_ADDR) + socket.inet_aton(ANY));

# setblocking(0) is equiv to settimeout(0.0) which means we poll the socket.
# But this will raise an error if recv() or send() can't immediately find or send data. 
sock.setblocking(0)

while 1:
    try:
        data, addr = sock.recvfrom(1024)
    except socket.error as e:
        pass
    else:
        print "From: ", addr
        print "Data: ", data

Here's some sample output from my Windows PC:

From:  ('0.0.0.0', 31801)
Data:  EDCP

Note the remote hardware device does not have an IP address and is using address 0.0.0.0

EDIT: I've now found that this also doesn't work on my Windows laptop. So, it doesn't look like it's specific to the OS. Furthermore, I've tried running another script to send multicast data to the same multicast address and port. I can send from one PC and all the others are able to receive correctly using my receive script. But, only my one Windows PC is able to receive the data from the hardware device in question. I'm wondering if it is something to do with the ethernet adapters or their configuration. Could it be something to do with the fact that the harware device has IP address 0.0.0.0 and that these ethernet adapters and/or my receiver script needs told to receive messages with this address? Running Wireshark on the Linux PCs sees the data from the hardware device.


回答1:


Try binding to the multicast group address instead:

sock.bind((MCAST_ADDR,MCAST_PORT))

Also, you don't need to set multicast TTL on the receiver, that's for senders, and also optional.




回答2:


I fought this same issue for two days. Wireshark saw the packets but my code did not. None of the supposedly "definitive" answers from various sources worked for me. The key came from https://serverfault.com/questions/163244/linux-kernel-not-passing-through-multicast-udp-packets.

Running "ip maddr" showed that code similar to yours was not adding the multicast address to any interface. I forced it to be added with smcroute (see link above). Still no joy. The packets have a source IP of 172.22... My interface is 172.17... I added a 172.22 address to that NIC. Bingo! Now my code received the packets.

Now how to make the program work without smcroute? I commented out the setsockopt() calls. Still worked. Unlinked the multicast address with smcroute -- failed. Uncommented the setsockopt() calls and replaced "ANY" with my 172.22 address. Success!

Summary:

  1. Make sure you have an IP on the same network segment as the incoming packets.
  2. Use that address in the IP_ADD_MEMBERSHIP call instead of INADDR_ANY.

It's possible you won't need to do 2) if you only have one NIC. I have three and must do it.

In case it's germane, I'm using Ubuntu 12.04. I did not need to change any of the default /etc/sysctl.conf settings as others have described. I tried them. They did not help, so I reset them back to installation defaults.



来源:https://stackoverflow.com/questions/15278053/receive-multicast-udp-datagrams-with-python-on-linux

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!