在多宿主Windows PC上接收多播消息
我正在一台PC上开发一个诊断工具,它有几个基于多播/udp的网络接口。用户可以选择NIC,应用程序创建套接字,将其绑定到此NIC,并将其添加到特定的多播组 多播消息的发送工作正常。但是,只有在我将套接字绑定到电脑的特定NIC时,消息接收才会成功。这几乎就像Windows中有一个用于接收多播消息的“默认”NIC,它始终是GetAdapterInfo函数返回的第一个NIC 我用Wireshark监控网络,发现“IGMP加入组”消息不是从我绑定套接字的NIC发送的,而是通过这个“默认”NIC发送的 如果禁用此NIC(或删除网线),则GetAdapterInfo返回的列表中的下一个NIC将用于接收多播消息 我通过在电脑的路由表中添加一个额外的条目成功地更改了这个“默认”NIC,但我认为这不是解决问题的好办法 下面附加的代码也会出现问题。加入组消息不是通过192.168.52发送的,而是通过不同的NIC发送的在多宿主Windows PC上接收多播消息,windows,sockets,udp,multicast,multihomed,Windows,Sockets,Udp,Multicast,Multihomed,我正在一台PC上开发一个诊断工具,它有几个基于多播/udp的网络接口。用户可以选择NIC,应用程序创建套接字,将其绑定到此NIC,并将其添加到特定的多播组 多播消息的发送工作正常。但是,只有在我将套接字绑定到电脑的特定NIC时,消息接收才会成功。这几乎就像Windows中有一个用于接收多播消息的“默认”NIC,它始终是GetAdapterInfo函数返回的第一个NIC 我用Wireshark监控网络,发现“IGMP加入组”消息不是从我绑定套接字的NIC发送的,而是通过这个“默认”NIC发送的 如
// socket_tst.cpp : Defines the entry point for the console application.
//
\#include tchar.h
\#include winsock2.h
\#include ws2ipdef.h
\#include IpHlpApi.h
\#include IpTypes.h
\#include stdio.h
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA m_wsaData;
SOCKET m_socket;
sockaddr_in m_sockAdr;
UINT16 m_port = 319;
u_long m_interfaceAdr = inet_addr("192.168.1.52");
u_long m_multicastAdr = inet_addr("224.0.0.107");
int returnValue = WSAStartup(MAKEWORD(2,2), &m_wsaData);
if (returnValue != S_OK)
{
return returnValue;
}
// Create sockets
if (INVALID_SOCKET == (m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) )
{
return WSAGetLastError();
}
int doreuseaddress = TRUE;
if (setsockopt(m_socket,SOL_SOCKET,SO_REUSEADDR,(char*) &doreuseaddress,sizeof(doreuseaddress)) == SOCKET_ERROR)
{
return WSAGetLastError();
}
// Configure socket addresses
memset(&m_sockAdr,0,sizeof(m_sockAdr));
m_sockAdr.sin_family = AF_INET;
m_sockAdr.sin_port = htons(m_port);
m_sockAdr.sin_addr.s_addr = m_interfaceAdr;
//bind sockets
if ( bind( m_socket, (SOCKADDR*) &m_sockAdr, sizeof(m_sockAdr) ) == SOCKET_ERROR )
{
return WSAGetLastError();
}
// join multicast
struct ip_mreq_source imr;
memset(&imr,0,sizeof(imr));
imr.imr_multiaddr.s_addr = m_multicastAdr; // address of multicastgroup
imr.imr_sourceaddr.s_addr = 0; // sourceaddress (not used)
imr.imr_interface.s_addr = m_interfaceAdr; // interface address
/* first join multicast group, then registerer selected interface as
* multicast sending interface */
if( setsockopt( m_socket
,IPPROTO_IP
,IP_ADD_MEMBERSHIP
,(char*) &imr
, sizeof(imr))
== SOCKET_ERROR)
{
return SOCKET_ERROR;
}
else
{
if( setsockopt(m_socket
,IPPROTO_IP
,IP_MULTICAST_IF
,(CHAR*)&imr.imr_interface.s_addr
,sizeof(&imr.imr_interface.s_addr))
== SOCKET_ERROR )
{
return SOCKET_ERROR;
}
}
printf("receiving msgs...\n");
while(1)
{
// get inputbuffer from socket
int sock_return = SOCKET_ERROR;
sockaddr_in socketAddress;
char buffer[1500];
int addressLength = sizeof(socketAddress);
sock_return = recvfrom(m_socket, (char*) &buffer, 1500, 0, (SOCKADDR*)&socketAddress, &addressLength );
if( sock_return == SOCKET_ERROR)
{
int wsa_error = WSAGetLastError();
return wsa_error;
}
else
{
printf("got message!\n");
}
}
return 0;
}
谢谢你的帮助 您可能需要检查/更改路由表。其中将有一个多播(224.0.0.0,子网240.0.0.0)流量的路由及其相应的度量:
C:\Users\Cetra>netstat -rn
*****
IPv4 Route Table
===========================================================================
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.80.254 192.168.80.99 20
127.0.0.0 255.0.0.0 On-link 127.0.0.1 306
127.0.0.1 255.255.255.255 On-link 127.0.0.1 306
127.255.255.255 255.255.255.255 On-link 127.0.0.1 306
192.168.80.0 255.255.255.0 On-link 192.168.80.99 276
192.168.80.99 255.255.255.255 On-link 192.168.80.99 276
192.168.80.255 255.255.255.255 On-link 192.168.80.99 276
224.0.0.0 240.0.0.0 On-link 127.0.0.1 306
224.0.0.0 240.0.0.0 On-link 192.168.80.99 276
255.255.255.255 255.255.255.255 On-link 127.0.0.1 306
255.255.255.255 255.255.255.255 On-link 192.168.80.99 276
******
问题是一个简单的打字错误。 如果使用选项ip\u MULTICAST\u if,则必须使用结构而不是结构ip\u mreq\u source。(IP_添加_源_成员资格选项需要另一个结构)
使用错误的结构很可能导致setsockeopt函数在预期NIC IP地址的位置找到零。零也是INADDR_ANY常量的值,该常量选择系统的默认NIC.:-) 谢谢你的回复。向路由表中添加/更改多播条目是一个有效的工作方法。但我很可能无法更改客户PC的路由表。我不认为这是一个解决办法,这只是网络的工作方式。您的客户的PC机也会是多主机的吗?因为应用程序是一种产品,我不能排除这一点。我已经考虑过使用windows API函数更改路由表。。。但我不确定这是否会对客户的电脑产生一些副作用。因此我放弃了这个想法。如果你自动更改它,它不会有太多的信任。如果您的设置对话框中列出了所有接口,并且在更改时有免责声明,即“这将更改多播流量的路由,您确定吗?是/否”。是的,这将是一种更好的方法:-)但是,我仍然很难相信,没有办法强迫套接字使用特定NIC发送多播IGMP连接消息。那对我来说毫无意义。