我正在尝试为在Linux主机上运行的非特权进程之间的高性能广播/多播通信找到一个简单的解决方案。我正在寻找一个解决方案,1)简单,2)无特权(无根),3)语言无关,4)面向数据包和5)高效(Gbit / s和更高)。
为了将其置于上下文中,我现有的代码只使用UDP套接字进行单播通信,这完全符合上述要求(除了单播)。我已经考虑通过让多个程序监听相同的UDP端口(使用SO_REUSEADDR
和/或SO_REUSEPORT
)将其扩展到多播,但这实际上并不是将数据包的副本分发给所有过程
我还研究过使用环回广播(127.255.255.255)来实现多个监听过程,但似乎我需要绑定到回送设备上的多个IP地址才能实现此功能,并添加这些地址需要root。
答案 0 :(得分:0)
根据Pete的建议,我找到了以下解决方案,其中太复杂。
以下Python 2程序通过多播/环回实现简单的聊天程序。在Linux 3.13 / Ubuntu 14.04上测试。
import os, socket, sys
# Use an administratively scoped multicast IP (RFC 2365).
mcast_group = '239.0.0.0'
port = 1234
# Communicate over the loopback interface.
ifc = '127.0.0.1'
def send(data):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
# Send over loopback interface.
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF,
socket.inet_aton(ifc))
sock.sendto(data, (mcast_group, port))
def listen():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
# Join group.
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(mcast_group) + socket.inet_aton(ifc))
# Allow multiple subscribers.
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((mcast_group, port))
while True:
data, remote = sock.recvfrom(1024)
print '#%d (%s:%d): %s' % ( (os.getpid(),) + remote + (data,) )
args = ' '.join(sys.argv[1:])
if args:
send(args)
else:
listen()
通过设置ifc = '0.0.0.0'
并取消设置IP_MULTICAST_IF
选项,可以轻松扩展到本地广播网段(LAN)之间的通信。
接收自己的流量
唯一的问题是似乎没有简单的方法来加入群组并发送给群组中的每个人 else 而不会获得自己的流量(即使使用相同的套接字进行收听)并发送)。
IPPROTO_IP
套接字选项IP_MULTICAST_LOOP
不起作用;使用环回接口时无效,当通过网络进行通信时,它会阻止其他本地客户端接收消息。
我可以通过过滤源地址来解决这个问题。
(作为旁注,我刚刚意识到QEMU包含native support用于使用多播发送虚拟网络流量。Faced with the above problem, QEMU开发人员还讨论了基于源地址的过滤,尽管看起来他们从不实际上它做了一些事情。结果,QEMU VM收到了自己的传出流量的副本,尽管流量通常在网络堆栈中被拒绝。)