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.
解决方案
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:
Make sure you have an IP on the same network segment as the incoming packets.
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.
本文描述了作者在Linux上用Python接收多播UDP数据时遇到的问题,即代码在Windows上正常工作但在Linux上无法接收到数据。经过排查,问题在于接口未加入多播地址。解决方案是确保接口拥有与数据包相同网络段的IP,并在IP_ADD_MEMBERSHIP调用中使用该IP,而不是使用INADDR_ANY。在某些情况下,可能仅需要完成第一步。

被折叠的 条评论
为什么被折叠?



