为什么在同一端口上但来自不同组的多播消息会合并在一起?
Why are multicast messages on the same port but from different groups combined?
在 Ubuntu 14.04 服务器上,我有两个进程,每个进程都在同一端口上侦听来自不同组的多播消息。我不会预料到这一点,但每个人都看到来自他们想要的组和另一个组的流量。
据我所知,这是已知行为(尽管我会称之为问题)。我发现 this SO question,它提供了一些用于确定从中接收数据的多播组的技术,但它并没有回答为什么会发生这种情况的问题。我原以为底层系统网络代码会过滤掉我不想接收的多播组上的消息。
虽然我主要使用 C++,但我可以提供一些简单的 Python 代码来演示问题。在一个终端 window 我监听多播组 239.1.1.1,端口 12345。在同一台服务器上的另一个终端 window 我监听多播组 239.2.2.2,也是端口 12345。在第二台机器上,我在 239.1.1.1:12345 上发送一条多播消息,在 239.2.2.2:12345 上发送另一条消息。
在 svr3 上,发射器:
rcook@svr3:~$ mcast_snd 239.1.1.1 12345 "from 1.1.1"
multicasting from 1.1.1 to 239.1.1.1 port 12345
rcook@svr3:~$ mcast_snd 239.2.2.2 12345 "from 2.2.2"
multicasting from 2.2.2 to 239.2.2.2 port 12345
在svr2上,window1,第一个接收者:
rcook@svr2:~$ mcast_rcv 239.1.1.1 12345
listening for multicast data on 239.1.1.1 port 12345
received 10 bytes: from 1.1.1
received 10 bytes: from 2.2.2
在 svr2,终端 2,另一个接收器:
rcook@svr2:~$ mcast_rcv 239.2.2.2 12345
listening for multicast data on 239.2.2.2 port 12345
received 10 bytes: from 1.1.1
received 10 bytes: from 2.2.2
如您所见,两个接收者都收到了两条消息。有人可以解释这是为什么吗?如果有更好的方法可以设置收件人不接收来自其他群组的消息,也请分享。
作为参考,这里是 mcast_rcv 的代码:
#!/usr/bin/python
import socket
import struct
import sys
if len(sys.argv) != 3:
print 'usage:', sys.argv[0], '<multicast group>', '<multicast port>'
sys.exit(0)
mcast_group = sys.argv[1]
mcast_port = int(sys.argv[2])
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', mcast_port))
mreq = struct.pack('4sl', socket.inet_aton(mcast_group), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
print 'listening for multicast data on', mcast_group, 'port', mcast_port
while True:
msg = sock.recv(10240)
print 'received', len(msg), 'bytes:', msg
这里是 mcast_snd 的代码:
#!/usr/bin/python
import socket
import sys
if len(sys.argv) != 4:
print 'usage:', sys.argv[0], '<multicast group>', '<multicast port>', '<mess
age>'
sys.exit(0)
mcast_group = sys.argv[1]
mcast_port = int(sys.argv[2])
message = sys.argv[3]
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
print 'multicasting', message, 'to', mcast_group, 'port', mcast_port
sock.sendto(message, (mcast_group, mcast_port))
问题已解决。我需要在接收器中指定要绑定的多播组,而不仅仅是端口。 This SO question 给我提供了线索。通过在 Python 代码中将地址保留为 ''
,或者在我的 C++ 中将地址保留为 INADDR_ANY
,我基本上是在告诉 OS 我想要该端口上的所有消息,而不管组。系统一如既往地为我提供了我想要的东西。
如果我将 sock.bind(('', mcast_port))
行替换为 mcast_rcv 中的 sock.bind((mcast_group, mcast_port))
,则行为符合我的预期和要求。仅加入多播组 (sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
) 不足以过滤掉该端口上的非组消息。
与 Receving multiple multicast feeds on the same port - C, Linux 的主要区别在于您使用的是 python。
在 mcast_rcv
中,您可以启用组过滤器禁用 IP_MULTICAST_ALL
选项,让 INADDR_ANY
像这样:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', mcast_port))
mreq = struct.pack('4sl', socket.inet_aton(mcast_group), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# disable mc_all
if hasattr(socket,'IP_MULTICAST_ALL') != True:
socket.IP_MULTICAST_ALL = 49
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_ALL, 0)
由于我使用的python没有定义socket.IP_MULTICAST_ALL
,可能需要定义它。
在 Ubuntu 14.04 服务器上,我有两个进程,每个进程都在同一端口上侦听来自不同组的多播消息。我不会预料到这一点,但每个人都看到来自他们想要的组和另一个组的流量。
据我所知,这是已知行为(尽管我会称之为问题)。我发现 this SO question,它提供了一些用于确定从中接收数据的多播组的技术,但它并没有回答为什么会发生这种情况的问题。我原以为底层系统网络代码会过滤掉我不想接收的多播组上的消息。
虽然我主要使用 C++,但我可以提供一些简单的 Python 代码来演示问题。在一个终端 window 我监听多播组 239.1.1.1,端口 12345。在同一台服务器上的另一个终端 window 我监听多播组 239.2.2.2,也是端口 12345。在第二台机器上,我在 239.1.1.1:12345 上发送一条多播消息,在 239.2.2.2:12345 上发送另一条消息。
在 svr3 上,发射器:
rcook@svr3:~$ mcast_snd 239.1.1.1 12345 "from 1.1.1"
multicasting from 1.1.1 to 239.1.1.1 port 12345
rcook@svr3:~$ mcast_snd 239.2.2.2 12345 "from 2.2.2"
multicasting from 2.2.2 to 239.2.2.2 port 12345
在svr2上,window1,第一个接收者:
rcook@svr2:~$ mcast_rcv 239.1.1.1 12345
listening for multicast data on 239.1.1.1 port 12345
received 10 bytes: from 1.1.1
received 10 bytes: from 2.2.2
在 svr2,终端 2,另一个接收器:
rcook@svr2:~$ mcast_rcv 239.2.2.2 12345
listening for multicast data on 239.2.2.2 port 12345
received 10 bytes: from 1.1.1
received 10 bytes: from 2.2.2
如您所见,两个接收者都收到了两条消息。有人可以解释这是为什么吗?如果有更好的方法可以设置收件人不接收来自其他群组的消息,也请分享。
作为参考,这里是 mcast_rcv 的代码:
#!/usr/bin/python
import socket
import struct
import sys
if len(sys.argv) != 3:
print 'usage:', sys.argv[0], '<multicast group>', '<multicast port>'
sys.exit(0)
mcast_group = sys.argv[1]
mcast_port = int(sys.argv[2])
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', mcast_port))
mreq = struct.pack('4sl', socket.inet_aton(mcast_group), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
print 'listening for multicast data on', mcast_group, 'port', mcast_port
while True:
msg = sock.recv(10240)
print 'received', len(msg), 'bytes:', msg
这里是 mcast_snd 的代码:
#!/usr/bin/python
import socket
import sys
if len(sys.argv) != 4:
print 'usage:', sys.argv[0], '<multicast group>', '<multicast port>', '<mess
age>'
sys.exit(0)
mcast_group = sys.argv[1]
mcast_port = int(sys.argv[2])
message = sys.argv[3]
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
print 'multicasting', message, 'to', mcast_group, 'port', mcast_port
sock.sendto(message, (mcast_group, mcast_port))
问题已解决。我需要在接收器中指定要绑定的多播组,而不仅仅是端口。 This SO question 给我提供了线索。通过在 Python 代码中将地址保留为 ''
,或者在我的 C++ 中将地址保留为 INADDR_ANY
,我基本上是在告诉 OS 我想要该端口上的所有消息,而不管组。系统一如既往地为我提供了我想要的东西。
如果我将 sock.bind(('', mcast_port))
行替换为 mcast_rcv 中的 sock.bind((mcast_group, mcast_port))
,则行为符合我的预期和要求。仅加入多播组 (sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
) 不足以过滤掉该端口上的非组消息。
与 Receving multiple multicast feeds on the same port - C, Linux 的主要区别在于您使用的是 python。
在 mcast_rcv
中,您可以启用组过滤器禁用 IP_MULTICAST_ALL
选项,让 INADDR_ANY
像这样:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', mcast_port))
mreq = struct.pack('4sl', socket.inet_aton(mcast_group), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# disable mc_all
if hasattr(socket,'IP_MULTICAST_ALL') != True:
socket.IP_MULTICAST_ALL = 49
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_ALL, 0)
由于我使用的python没有定义socket.IP_MULTICAST_ALL
,可能需要定义它。