【问题标题】:IP_ADD_MEMBERSHIP fails when set both on interface and its subinterface; is that expected?IP_ADD_MEMBERSHIP 在接口及其子接口上都设置时失败;这是预期的吗?
【发布时间】:2018-09-23 22:22:39
【问题描述】:

我正在调试3rd-party network application 并试图弄清楚为什么它在使用IP_ADD_MEMBERSHIP 调用setsockopt 来设置多播组时会报告错误。该应用程序是用 C++ 编写的,但我用 python 编写了一个 MWE,它复制了相同的系统调用:

import socket
import struct

ETH0_IP = "192.168.88.85"
ETH0_1_IP = "192.168.88.254"

MULTICAST_IP = "224.0.0.7"

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
ip = socket.inet_aton(ETH0_IP)
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, ip)
group = struct.pack("4s4s", socket.inet_aton(MULTICAST_IP), ip)
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group)
# s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)

s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
ip2 = socket.inet_aton(ETH0_1_IP)
s2.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, ip2)
group2 = struct.pack("4s4s", socket.inet_aton(MULTICAST_IP), ip2)

# the second group is added to the first socket so that we can only bind to one socket and read data from it
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group2)

在第二次IP_ADD_MEMBERSHIP 调用时,我收到错误OSError: [Errno 98] Address already in use

我发现只有当ETH0_1_IPETH_0_IP 的子接口时才会发生这种情况。而且我不确定这是否是预期的。如果是,有没有办法实际检测到这种情况并丢弃已绑定接口的子接口?此外,如果注册失败并出现上述错误,我的多播套接字是否会接收发送到子接口的数据?

为了完整起见:

$ cat /etc/network/interfaces
auto lo
iface lo inet loopback
iface lo inet6 loopback

auto eth0:1
iface eth0:1 inet static
    address 192.168.88.254
    netmask 255.255.240.0

【问题讨论】:

  • 这是接收方代码还是发送方代码?
  • 不确定,该应用程序同时具有服务器和客户端部分,但是在启动服务器时会显示此错误消息,因此我认为它应该与接收器部分连接。
  • 这意味着它是一个发件人/服务器。我不是这方面的专家,但我认为您对套接字的使用可能是错误的。在这种情况下,我会查看来自 github 的一些工作,例如 github.com/hymanc/purpleproject1/blob/…github.com/bhuztez/ercraft/blob/…github.com/adamzfc/python_demo/blob/…,并找出做错了什么。通常可以绑定到子界面和主界面
  • 我认为您可以改进您的 python 示例并使其更清晰地删除注释行并删除未使用的第二个套接字s2
  • 据我了解,您所做的只是为现有物理适配器创建一个别名。由于这只是 Linux 的一个过时功能(在一个接口上配置多个 IP 地址),我猜测在幕后,它知道这是同一个接口,因此拒绝第二次尝试使用同一个接口。

标签: sockets networking multicast


【解决方案1】:

Linux 正在将您的别名接口作为同一接口进行跟踪,因此拒绝重新使用该接口的尝试。

更详细地说,我已经在 CentOS 7 上成功运行了您的代码,使用两个独立的物理接口,没有任何更改。如果我随后更改代码以在同一物理地址上使用别名,它会失败并出现与您看到的相同的错误。

进一步挖掘,我发现如果我转储物理适配器和别名的接口索引(使用 SIOCGIFINDEX),它们确实具有相同的索引。

如果您想使用 Python 自行检查,请快速查看 https://gist.github.com/firaxis/0e538c8e5f81eaa55748acc5e679a36e 中的一些代码(缺少 ctypes 和套接字的导入),然后尝试以下操作:

print(Interface(name="eth0").index)
print(Interface(name="eth0:1").index)

【讨论】:

  • 谢谢,看来代码应该检查接口号,并确保每个接口号只执行一次调用。
猜你喜欢
  • 2016-02-28
  • 1970-01-01
  • 1970-01-01
  • 2014-10-15
  • 1970-01-01
  • 2015-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多