Python-Windows上的多播绑定上的绑定错误 [英] Python - bind error on multicast bind on windows

查看:163
本文介绍了Python-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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆