我有一个广播 SSDP 发现请求的 Python 应用程序。我注意到我试图发现的设备并不总是响应。使用 Wireshark,我发现只有我的一些广播可以到达网络。经过一些故障排除后,我将问题的根源隔离到 SSDP 发现服务 - 如果我禁用该服务,那么我的数据包丢失就会消失。此外,如果我使用 SSDP (239.255.255.250) 以外的多播地址,问题也会消失。所以看起来 SSDP 肯定会限制我传出的 UDP 广播。知道这是为什么吗?也许试图合并广播/限制流量?我使用的是 Windows 7。在 OSX 下不会出现此问题。
这是一个演示数据包丢失的快速测试应用程序 - 两个实例在同一系统上运行,发送者实例每秒传输一个数据包,接收报告测试定义的数据包编号中的任何间隙。
def testSend():
seqNumber = 0
while True:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1)
sock.sendto(str(seqNumber), ("239.255.255.250", 1900))
sock.close()
print("Sent Seq #{:4d} [{}]".format(seqNumber, time.ctime()))
seqNumber += 1
time.sleep(1)
def testReceive():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("", 1900))
mreq = struct.pack("4sl", socket.inet_aton("239.255.255.250"), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
expectedSequenceNumber = 0
while True:
response = sock.recv(100)
actualSequenceNumber = int(response)
if actualSequenceNumber == expectedSequenceNumber:
print("Good: Received Seq #{:>4s} [{}]".format(response, time.ctime()))
else:
print("Bad: Expected Seq #{}, Got #{} ({} frames dropped) [{}]".format(expectedSequenceNumber, actualSequenceNumber, actualSequenceNumber - expectedSequenceNumber, time.ctime()))
expectedSequenceNumber = actualSequenceNumber + 1
if sys.argv[1] == 'send':
testSend()
elif sys.argv[1] == 'receive':
testReceive()
Output on receiving side:
Good: Received Seq # 0 [Sun Sep 20 11:01:18 2015]
Good: Received Seq # 1 [Sun Sep 20 11:01:19 2015]
Good: Received Seq # 2 [Sun Sep 20 11:01:20 2015]
Good: Received Seq # 3 [Sun Sep 20 11:01:21 2015]
Good: Received Seq # 4 [Sun Sep 20 11:01:22 2015]
Bad: Expected Seq #5, Got #12 (7 frames dropped) [Sun Sep 20 11:01:30 2015]
Good: Received Seq # 13 [Sun Sep 20 11:01:31 2015]
Good: Received Seq # 14 [Sun Sep 20 11:01:32 2015]
Good: Received Seq # 15 [Sun Sep 20 11:01:33 2015]
Good: Received Seq # 16 [Sun Sep 20 11:01:34 2015]
Good: Received Seq # 17 [Sun Sep 20 11:01:35 2015]
Good: Received Seq # 18 [Sun Sep 20 11:01:36 2015]
Good: Received Seq # 19 [Sun Sep 20 11:01:37 2015]
Good: Received Seq # 20 [Sun Sep 20 11:01:38 2015]
Bad: Expected Seq #21, Got #51 (30 frames dropped) [Sun Sep 20 11:02:09 2015]
Good: Received Seq # 52 [Sun Sep 20 11:02:10 2015]
Good: Received Seq # 53 [Sun Sep 20 11:02:11 2015]
Good: Received Seq # 54 [Sun Sep 20 11:02:12 2015]
Good: Received Seq # 55 [Sun Sep 20 11:02:14 2015]
Good: Received Seq # 56 [Sun Sep 20 11:02:15 2015]
Good: Received Seq # 57 [Sun Sep 20 11:02:16 2015]
Good: Received Seq # 58 [Sun Sep 20 11:02:17 2015]
Good: Received Seq # 59 [Sun Sep 20 11:02:18 2015]
Good: Received Seq # 60 [Sun Sep 20 11:02:19 2015]
Bad: Expected Seq #61, Got #71 (10 frames dropped) [Sun Sep 20 11:02:30 2015]
Good: Received Seq # 72 [Sun Sep 20 11:02:31 2015]
Good: Received Seq # 73 [Sun Sep 20 11:02:32 2015]
Good: Received Seq # 74 [Sun Sep 20 11:02:33 2015]
Good: Received Seq # 75 [Sun Sep 20 11:02:34 2015]
Good: Received Seq # 76 [Sun Sep 20 11:02:35 2015]
Good: Received Seq # 77 [Sun Sep 20 11:02:36 2015]
Good: Received Seq # 78 [Sun Sep 20 11:02:37 2015]
Good: Received Seq # 79 [Sun Sep 20 11:02:38 2015]
Good: Received Seq # 80 [Sun Sep 20 11:02:39 2015]
Bad: Expected Seq #81, Got #110 (29 frames dropped) [Sun Sep 20 11:03:09 2015]
Good: Received Seq # 111 [Sun Sep 20 11:03:10 2015]
Good: Received Seq # 112 [Sun Sep 20 11:03:11 2015]
Good: Received Seq # 113 [Sun Sep 20 11:03:12 2015]
Good: Received Seq # 114 [Sun Sep 20 11:03:13 2015]
Good: Received Seq # 115 [Sun Sep 20 11:03:14 2015]
Good: Received Seq # 116 [Sun Sep 20 11:03:15 2015]
Good: Received Seq # 117 [Sun Sep 20 11:03:16 2015]
Good: Received Seq # 118 [Sun Sep 20 11:03:17 2015]
Good: Received Seq # 119 [Sun Sep 20 11:03:18 2015]
Bad: Expected Seq #120, Got #130 (10 frames dropped) [Sun Sep 20 11:03:30 2015]
Good: Received Seq # 131 [Sun Sep 20 11:03:31 2015]
Good: Received Seq # 132 [Sun Sep 20 11:03:32 2015]
Good: Received Seq # 133 [Sun Sep 20 11:03:33 2015]
Good: Received Seq # 134 [Sun Sep 20 11:03:34 2015]
Good: Received Seq # 135 [Sun Sep 20 11:03:35 2015]
Good: Received Seq # 136 [Sun Sep 20 11:03:36 2015]
编辑(10/06/15):我相信我是这个问题的根源。Windows SSDP 发现服务会定期循环显示哪个接口多播数据包发出,以及哪些接口传入数据包,即使在仅配置/在线的一个物理网络接口的系统上也是如此。在我的系统上,我有一个有线以太网和两个虚拟 VMware 网络适配器(我没有在 VM 中运行——它们在主机端并且已启用但未使用)。我修改了上述实用程序的源代码,以支持通过 setsockopt(IP_MULTICAST_IF) 配置我的广播在哪个接口上发出,以及我通过 setsockopt(IP_ADD_MEMBERSHIP) 在哪个接口上收听广播。然后我运行了该实用程序的四个实例——一个在 INADDR_ANY 上发送,一个在 INADDR_ANY 上接收,还有两个监听每个 VMware 虚拟网络适配器(VMnet1 和 VMnet8,都预先配置了自己的制造/虚拟子网)。当 INADDR_ANY 接收器实例开始丢失数据包时,我看到它们出现在一个 VMware 侦听器上。这是我证明 Windows SSDP 发现服务正在循环为多播传输设置的默认适配器的证据。当 SSDP 服务被禁用时,我没有看到这种情况发生。我假设发现服务这样做是为了在所有网络接口上捕获 SSDP 消息,尽管目前尚不清楚为什么它必须更改系统默认多播来完成此操作,而不仅仅是在系统中的每个接口上拥有多个套接字。当 INADDR_ANY 接收器实例开始丢失数据包时,我看到它们出现在一个 VMware 侦听器上。这是我证明 Windows SSDP 发现服务正在循环为多播传输设置的默认适配器的证据。当 SSDP 服务被禁用时,我没有看到这种情况发生。我假设发现服务这样做是为了在所有网络接口上捕获 SSDP 消息,尽管目前尚不清楚为什么它必须更改系统默认多播来完成此操作,而不仅仅是在系统中的每个接口上拥有多个套接字。当 INADDR_ANY 接收器实例开始丢失数据包时,我看到它们出现在一个 VMware 侦听器上。这是我证明 Windows SSDP 发现服务正在循环为多播传输设置的默认适配器的证据。当 SSDP 服务被禁用时,我没有看到这种情况发生。我假设发现服务这样做是为了在所有网络接口上捕获 SSDP 消息,尽管目前尚不清楚为什么它必须更改系统默认多播来完成此操作,而不仅仅是在系统中的每个接口上拥有多个套接字。
解决方法是显式设置我为多播传输和侦听配置的接口,而不是依赖 INADDR_ANY,这是处理多播的传统方式,在所有其他单宿主操作系统平台上都可以正常工作。请注意,您不仅必须显式设置发送接口,还必须显式设置接收端,因为发现服务的默认接口循环适用于默认传输接口以及 IP 多播成员组接受哪个接口传入数据包.