2

我正在使用基于多播/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;
}

谢谢四爷的帮助!

4

2 回答 2

2

问题是一个简单的错字。如果使用选项 IP_MULTICAST_IF,则必须使用结构struct ip_mreq而不是使用结构struct ip_mreq_source 。(IP_ADD_SOURCE_MEMBERSHIP 选项需要其他结构)

使用错误的结构很可能会导致 setsockeopt 函数在预期的 NIC IP 地址处找到零。零也是 INADDR_ANY 常量的值,它选择系统的默认 NIC。:-)

于 2010-06-09T14:40:25.250 回答
1

您可能想要检查/更改您的路由表。那里将有一条用于多播(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

******
于 2010-06-07T10:49:26.140 回答