【问题标题】:Linux: OS support for an unprivileged interprocess busLinux:操作系统对非特权进程间总线的支持
【发布时间】:2014-06-02 11:21:52
【问题描述】:

我正在尝试为在 Linux 主机上运行的非特权进程之间的高性能广播/多播通信找到一个简单的解决方案。我正在寻找一种解决方案,它 1) 简单,2) 无特权(无 root),3) 与语言无关,4) 面向数据包和 5) 高效(Gbit/s 及以上)。

为了说明这一点,我现有的代码只是使用 UDP 套接字进行单播通信,这完全符合上述要求(单播除外)。我已经考虑通过让多个程序监听同一个 UDP 端口(使用SO_REUSEADDR 和/或SO_REUSEPORT)将其扩展到多播,但这实际上并没有将数据包的副本分发给所有进程。

我还研究过使用环回广播 (127.255.255.255) 来访问多个侦听进程,但似乎我需要绑定到环回设备上的多个 IP 地址才能使其正常工作,并添加这些地址需要root。

【问题讨论】:

  • 您必须使用address in the multicast address range 才能让所有进程都收到它。
  • 为此尝试使用 dbus 可能是值得的。它通常在常见的 Linux 操作系统中默认安装(并运行);它很健壮;它已成为一种惯用的 Linux 进行 IPC 的方式。
  • 我对任何涉及中间人进程的事情都持谨慎态度,因为额外的上下文切换和内存复制会严重影响性能。例如,one study 发现 DBus 比 Unix 套接字慢 15 倍。我知道自 2010 年以来已经在 DBus 性能方面做了很多工作,但到目前为止,多播 UDP 似乎更简单,而且毫无疑问也更快。

标签: linux sockets ipc broadcast


【解决方案1】:

根据 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 不起作用;使用 loopback 接口时无效,通过网络通信时会阻止其他本地客户端接收消息。

不过,我可以通过过滤源地址来解决这个问题。

(作为旁注,我刚刚意识到 QEMU 包含 native support 用于使用多播发送虚拟网络流量。Faced with the above problem, QEMU 开发人员还讨论了基于源地址的过滤,尽管他们似乎从未真正做过任何事情因此,QEMU VM 会收到一份自己的传出流量的副本,尽管该流量通常在网络堆栈中被拒绝。)

【讨论】:

  • 这也适用于 Windows 7,除了接收套接字必须绑定到接口单播地址或“任何”地址 (0.0.0.0),而不是多播地址。因此它也可以接收单播流量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
  • 2013-12-25
  • 2018-03-20
  • 1970-01-01
  • 1970-01-01
  • 2017-01-28
相关资源
最近更新 更多