3

我有一个广播 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 多播成员组接受哪个接口传入数据包.

4

0 回答 0