我正在具有基于多播/udp的多个网络接口(interface)的PC上开发诊断工具。用户可以选择一个NIC,应用程序将创建套接字,然后将其绑定(bind)到该NIC并将其添加到特定的多播组。

多播消息的发送工作正常。但是,仅当我将套接字绑定(bind)到PC的特定NIC时,消息接收才会成功。几乎看起来像Windows中有一个“默认” NIC来接收多播消息,它始终是 GetAdapterInfo 函数返回的第一个NIC。

我用Wireshark监视了网络,发现“IGMP Join Group”消息不是从绑定(bind)套接字的NIC发送的,而是由“默认” NIC发送的。

如果禁用此NIC(或断开网络电缆),则GetAdapterInfo返回的列表的下一个NIC将用于接收多播消息。

通过在PC的路由表中添加其他条目,我成功地更改了此“默认” NIC,但是我认为这不是解决问题的好方法。

使用下面附加的代码也会发生此问题。加入组消息不是通过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;
}

谢谢四个您的帮助!

最佳答案

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

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

关于windows - 在多宿主Windows PC上接收多播消息,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2988788/

10-11 00:44