2013-03-10 34 views
3

我需要在Python應用程序中使用多播,google搜索了一下後,我發現其中運行的代碼片段,那就是:的Python - 組播綁定綁定錯誤在Windows

# 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)意味着我想收到自帶此插口,並在該端口上的所有流量,不管包(同0.0.0.0)的目的IP的,讓我們稱之爲這種情況下1

而且這個工作,如果我有bind((addr,port))。我將接收所有包含目的地IP地址的數據包(當然,我也需要加入這個多播組),這是案例2.

現在我說這兩個作品,但只在Linux上。

我嘗試在Windows機器上我的小程序,第一種情況是工作,但是當我嘗試另一個我得到

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)這個錯誤。

回答

3

PYMOTW Multicast articleCarl Cerecke in the comments所述,在Windows中使用socket.INADDR_ANY將綁定到默認的多播地址,並且如果您有多個接口,Windows可能會選擇錯誤的接口。

爲了解決這個問題,你可以明確地指定要由接收多播消息的接口:

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) 

你可以使用該接口的列表如下:

socket.gethostbyname_ex(socket.gethostname()) 
# ("PCName", [], ["169.254.80.80", "192.168.1.10"]) 

在上面的例子中,我們可能希望跳過第一個169.254鏈路本地地址並選擇所需的192.168.1.10地址。

socket.gethostbyname_ex(socket.gethostname())[2][1] 
# "192.168.1.10"