我正在使用基于多播/udp 的多个网络接口的 PC 上开发诊断工具。用户可以选择一个 NIC,应用程序创建套接字,将它们绑定到这个 NIC 并将它们添加到特定的多播组。
多播消息的发送工作正常。但是,只有当我将套接字绑定到我的 PC 的特定 NIC 时,才能成功接收消息。它几乎看起来像在 Windows 中有一个用于接收多播消息的“默认”NIC,它始终是GetAdapterInfo函数返回的第一个 NIC。
我使用 Wireshark 监控网络,发现“IGMP 加入组”消息不是从我绑定套接字的 NIC 发送的,而是通过这个“默认”NIC 发送的。
如果我禁用此网卡(或移除网线),GetAdapterInfo 返回的列表中的下一个网卡将用于接收多播消息。
我通过在我的 PC 的路由表中添加一个附加条目成功地更改了这个“默认”网卡,但我认为这不是解决问题的好方法。
下面附加的代码也会出现问题。加入组消息不是通过 192.168.52 发送的,而是通过不同的 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;
}
谢谢四爷的帮助!