3

Python アプリケーションでマルチキャストを使用する必要があります。少しグーグルで調べたところ、機能するコードのスニペットが見つかりました。

# 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 と呼びましょう。

また、これは私が持っている場合に機能します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 を使用しました)。

4

1 に答える 1