Python-Windows上的多播绑定上的绑定错误 [英] Python - bind error on multicast bind on windows
问题描述
我需要在Python应用程序中使用多播,在进行了一段时间的搜索之后,我发现了一些有效的代码段,如下所示:
I need to use multicast in Python application, after googling a bit I found snippets of code that works, here it is:
# UDP multicast examples, Hugo Vincent, 2005-05-14.
import socket
import sys
import struct
def send(data, port=50000, addr='239.192.1.100'):
"""send(data[, port[, addr]]) - multicasts a UDP datagram."""
# Create the socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Make the socket multicast-aware, and set TTL.
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
# Send the data
s.sendto(data, (addr, port))
def recv(port=50000, addr="239.192.1.100", buf_size=1024):
"""recv([port[, addr[,buf_size]]]) - waits for a datagram and returns the data."""
# Create the socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Set some options to make it multicast-friendly
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
except AttributeError:
pass # Some systems don't support SO_REUSEPORT
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20)
# Bind to the port
s.bind(('', port))
# Set some more multicast options
intf = socket.gethostbyname(socket.gethostname())
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf))
mreq = struct.pack("4sl", socket.inet_aton(addr), socket.INADDR_ANY)
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# Receive the data, then unregister multicast receive membership, then close the port
data, sender_addr = s.recvfrom(buf_size)
s.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP, socket.inet_aton(addr) + socket.inet_aton('0.0.0.0'))
s.close()
return data
if __name__=="__main__":
if sys.argv[1] == "recv":
print recv()
else:
send("a")
绑定和多播有问题.
据我了解,如果我绑定接收消息的套接字,在这种情况下,它将过滤流量. ('',port)
表示我想接收来自此套接字和此端口的所有流量,而不管数据包的目标ip(与0.0.0.0
相同),让我们称之为情况1.
As I understand if I bind my socket on which I will receive messages, in this case it will filter the traffic. ('',port)
means I want to receive all traffic that comes on this socket and this port, regardless of the destination ip of the packet (same as 0.0.0.0
), lets call this case 1.
如果我有bind((addr,port))
,这也有效.我将收到目标IP为该多播组的所有数据包(当然,我也需要加入此多播组),这是情况2.
Also this works if I have bind((addr,port))
. I will receive all packets with destination ip being this multicast group (of course I also need to join this multicast group), this is case 2.
现在,正如我所说的,这两种方法都有效,但仅适用于Linux.
Now as I said both of these works, but only on Linux.
我在Windows机器上尝试了我的小程序,第一种情况正在工作,但是当我尝试另一种时,我就得到了
I tried my little program on windows machine, first case is working but when I try the other one I am getting
Traceback (most recent call last):
File "test.py", line 51, in <module>
print recv()
File "test.py", line 32, in recv
s.bind((addr, port))
File "C:\Python27\lib\socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 10049] The requested address is not valid in its context
我不是Windows系统专家(我主要在Linux上进行开发),但我很感兴趣,为什么我的代码仅在Windows系统(我使用Windows 7 btw)上失败并出现此错误.
I am no expert on windows systems (I mainly do my development on Linux) but I am interested why my code fails with this error only on windows systems (I used windows 7 btw).
推荐答案
如在 PYMOTW多播文章的评论中使用Carl Cerecke, Windows中的socket.INADDR_ANY将绑定到默认的多播地址,并且如果您有多个接口,Windows可能会选择错误的接口.
As noted by Carl Cerecke in the comments of the PYMOTW Multicast article, the use of socket.INADDR_ANY in Windows will bind to the default multicast address and if you have more than one interface Windows has the potential to pick the wrong one.
为了解决这个问题,您可以显式指定要从其接收多播消息的接口:
In order to get around this, you can explicitly specify the interface you want to receive multicast messages from:
group = socket.inet_aton(multicast_group)
iface = socket.inet_aton('192.168.1.10') # listen for multicast packets on this interface.
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group+iface)
您可以使用以下方法获取接口列表:
You can get a list of interfaces using the following:
socket.gethostbyname_ex(socket.gethostname())
# ("PCName", [], ["169.254.80.80", "192.168.1.10"])
在上面的示例中,我们可能希望跳过第一个169.254链接本地地址,然后选择所需的192.168.1.10地址.
In the above example, we would likely want to skip over the first 169.254 link-local address and select the desired 192.168.1.10 address.
socket.gethostbyname_ex(socket.gethostname())[2][1]
# "192.168.1.10"
这篇关于Python-Windows上的多播绑定上的绑定错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!