7

マルチキャストUDPoverlocalhostを使用して、単一のマシンで実行されている協調プログラムの緩いコレクションを実装しています。次のコードは、Mac OSX、Windows、およびLinuxで適切に機能します。欠陥は、コードがローカルホストネットワークの外部でもUDPパケットを受信することです。たとえばsendSock.sendto(pkt, ('192.168.0.25', 1600))、ネットワーク上の別のボックスから送信されたときに、テストマシンによって受信されます。

import platform, time, socket, select

addr = ("239.255.2.9", 1600)

sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 24)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, 
    socket.inet_aton("127.0.0.1"))

recvSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
if hasattr(socket, 'SO_REUSEPORT'):
    recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)

recvSock.bind(("0.0.0.0", addr[1]))
status = recvSock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, 
    socket.inet_aton(addr[0]) + socket.inet_aton("127.0.0.1"));

while 1:
    pkt = "Hello host: {1} time: {0}".format(time.ctime(), platform.node())
    print "SEND to: {0} data: {1}".format(addr, pkt)
    r = sendSock.sendto(pkt, addr)

    while select.select([recvSock], [], [], 0)[0]:
        data, fromAddr = recvSock.recvfrom(1024)
        print "RECV from: {0} data: {1}".format(fromAddr, data)

    time.sleep(2)

しようとしましrecvSock.bind(("127.0.0.1", addr[1]))たが、ソケットがマルチキャストトラフィックを受信できなくなります。127/24ネットワークからのマルチキャストパケットのみを受け入れるようにrecvSockを構成する適切な方法はありますか、または受信した各パケットのアドレスをテストする必要がありますか?

4

4 に答える 4

5

ここでの他の回答で述べられていることに反して、IPv4は次のようにTTLベースのマルチキャストスコープをサポートします。

0: node-local (not forwarded outside the current host)
1: link-local (not forwarded outside the current subnet)
< 32: site-local
< 64: region-local
< 128: continent-local
< 255: global

(管理スコープのマルチキャストもサポートします。)

出典:WR Stevens、Unix Network Programming、第2版、第1巻、セクション19.2、RFC2365一致するように修正。

于 2013-02-20T21:50:07.060 に答える
2

残念ながら、マルチキャストIPにはそのような「サブネットワークによるフィルタリング」機能はありません。したがって、IPTables(Linuxの場合)またはシステム/ネットワークの同等の「ファイアウォール」SW / HWをいじって「ドロップオン」したい場合を除き、フロア」あなたが気に入らないすべてのマルチキャストパケット、私はあなたがアプリケーションレベルでそれをしなければならないと思います(fromAddr例えば、あなたの内側のループでテストをオンにします)。他のホストからのIPトラフィックが多すぎて、パフォーマンスが低下していませんか...?

于 2010-05-21T02:40:58.673 に答える
1

ホストがIPv6をサポートしている場合は、マルチキャストアドレスのスコープコンポーネント(これはマルチキャストプレフィックスFF0x :の「x」)を使用して、スコープ1(たとえば、ローカルホストの「ネームサービスサーバー」にのみIPv6マルチキャストアドレスFF01 :: 107を使用します)。残念ながら、IPv4マルチキャストメカニズムには明示的なスコープがなく、管理スコープのIPv4マルチキャスト範囲を定義するRFC 2365(http://tools.ietf.org/html/rfc2365)は、ノードローカルスコープアドレスを定義せず、リンクローカルスコープ範囲。

于 2011-03-17T14:38:11.420 に答える
0

マルチキャストソケットで127.0.0.1を使用connect()すると、IPスタックでフィルタリングできます。

デモ用にソースコードで更新

このスクリプトを1つのホストで複数回実行して、マルチキャストパケットが分散されていることを確認できます。

#!/usr/bin/python

import platform, time, socket, select

addr = ("239.255.2.9", 1600)

sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 24)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF,
    socket.inet_aton("127.0.0.1"))

recvSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
if hasattr(socket, 'SO_REUSEPORT'):
    recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)

recvSock.bind(("0.0.0.0", addr[1]))
status = recvSock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
    socket.inet_aton(addr[0]) + socket.inet_aton("127.0.0.1"));

sendSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
if hasattr(socket, 'SO_REUSEPORT'):
    sendSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
sendSock.bind(("127.0.0.1", addr[1]));
recvSock.connect(("127.0.0.1", addr[1]));

while 1:
    pkt = "Hello host: {1} time: {0}".format(time.ctime(), platform.node())
    print "SEND to: {0} data: {1}".format(addr, pkt)
    r = sendSock.sendto(pkt, addr)

    while select.select([recvSock], [], [], 0)[0]:
        data, fromAddr = recvSock.recvfrom(1024)
        print "RECV from: {0} data: {1}".format(fromAddr, data)

    time.sleep(2)

別のインターフェースからパケットを開始するには:

#!/usr/bin/python

import platform, time, socket, select

sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

pkt = "Hello from network.";
sendSock.sendto(pkt, ('10.65.42.129', 1600))

3つすべてをWindowsXPのCygwinで実行し、必要に応じて結果が正しいことを確認しました。

出力例

SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:15 2013
RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:14 2013
RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:15 2013
SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:17 2013
RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:16 2013
RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:17 2013

以前は、出力には外部パケットが表示されていました。次に例を示します。

SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:07:05 2013
RECV from: ('10.65.42.129', 4711) data: Hello from network.
RECV from: ('127.0.0.1', 4710) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:07:05 2013
SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:07:11 2013
RECV from: ('10.65.42.129', 4712) data: Hello from network.
于 2010-05-22T02:50:57.893 に答える