首页 文章

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

提问于
浏览
1

我有三个网络接口的计算机 - 一个真实和两个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 我关闭所有虚拟网络适配器并仅保持真正的适配器 . 在这种配置中,两个版本的代码(一个绑定到所有地址的套接字/每个接口一个套接字)工作正常 .

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

Pseudo code

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

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

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

相关问题