为什么我的套接字没有收到UDP多播?

时间:2014-07-24 13:39:36

标签: windows sockets udp multicast upnp

我的计算机有三个网络接口 - 一个是真实的,两个是VMWare虚拟的。我想从端口1900上的UPNP设备接收多播消息。

我尝试枚举所有适配器并为每个适配器创建一个套接字。另外,我设置套接字选项ReuseAddr,关闭ExclusiveAddrUse套接字选项,并将每个套接字添加到多播组239.255.255.250。我将socket绑定到addr:InterfaceAddr:1900

问题是只有一个套接字接收消息 - 一个VMWare网络套接字。 netstat -a -o -p UDP >netstat.txt向我显示我的所有插座都在倾听:

Proto  Local address          Peer address                           PID    App
UDP    0.0.0.0:1900           *:*                                    5248   uTorrent
UDP    127.0.0.1:1900         *:*                                    3932   myApp
UDP    127.0.0.1:1900         *:*                                    1400   svchost
UDP    192.168.0.100:1900     *:*                                    3932   myApp
UDP    192.168.0.100:1900     *:*                                    1400   svchost
UDP    192.168.139.1:1900     *:*                                    1400   svchost
UDP    192.168.139.1:1900     *:*                                    3932   myApp       +
UDP    192.168.180.1:1900     *:*                                    1400   svchost
UDP    192.168.180.1:1900     *:*                                    3932   myApp

仅标有' +'接收UPNP多播。但Wireshark告诉我,还有很多其他数据包都没有被我收到。我哪里错了?

UPD1 我的代码在主机上运行(Windows 7),此时没有运行虚拟机。我的真实网络中有一些UPNP设备(路由器等) - 192.168.0。*也会发送一些通知,但我无法接收它们。通过虚拟网络192.168.139。*发送UPNP NOTIFY消息由主机(ms播放器/渲染器/等)发送。此类通知也通过所有可用网络发送,但我仅在192.168.139.1接口上接收它们。

UPD2 我重写了我的代码以使用单个套接字并将其绑定到INADDR_ANY:1900。我第一次启动新版本时一切正常 - 我通过虚拟或真实网络从所有设备收到所有UPNP消息。但是下次当我启动我的应用程序时,我可以看到只接收来自192.168.139。* net的通知 - 所有这些都与开始问题一样。

UPD3 我关闭所有虚拟网络适配器并继续使用真正的适配器。在这种配置中,两个版本的代码(一个绑定到所有地址的套接字/每个接口一个套接字)都可以正常工作。

关于MCVE 制作MCVE并不容易,所以现在我试图通过症状了解发生的情况。

伪码

hSock = :: socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );

u_long nb = 1;
::ioctlsocket( hSock, FIONBIO, &nb);

reuseAddrSet(hSock, TRUE);
reusePortSet(hSock, TRUE);

if (useSingleSocket)
    bindSocket(hSock, "any-addr");
else
    bindSocket(hSock, "interface-addr");

broadcastModeSet(hSock, TRUE);

setSockOption( hSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, { "any-addr", "239.255.255.250" } );

UPD4 我发现了关于多播的下一条说明(此处为http://www4.ncsu.edu/~rhee/clas/csc495j/mcast.api.txt):

  

每个成员资格都与一个界面相关联,而且它是   可以在多个接口上加入同一个组。   " imr_interface"应该是INADDR_ANY来选择默认多播   接口,或主机的本地地址之一,以选择特定的   (支持多播)接口。最高IP_MAX_MEMBERSHIPS(目前为20)   可以在单个套接字上添加成员资格。

如上所述,代码

setSockOption( hSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, { "any-addr", "239.255.255.250" }

仅将默认多播接口添加到多播组,而不是所有接口,正如我最初假设的那样。所以,我需要枚举接口并调用

setSockOption( hSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, { "interface-addr", "239.255.255.250" }

表示单个套接字,或者为每个每个接口套接字调用它,其地址与用于绑定soxket的地址相同。

我没错?

1 个答案:

答案 0 :(得分:0)

如在UPD4中所写,套接字用户必须使用接口地址将套接字添加到组播组。将套接字添加到组播组时使用INADDR_ANY仅将默认组播接口添加到组播组,因此只有一个接口可以接收组播消息。

另外,正如我们所知,套接字组播组的数量存在操作系统限制,因此更好的方法是为每个网络接口创建一个套接字。

相关问题