加入多播组时调用setsockopt时出现“No such device”错误

cvxl0en2  于 2023-03-11  发布在  其他
关注(0)|答案(4)|浏览(444)

我有一个发送多播数据报的代码。一个关键的代码:

uint32_t port;
int sockfd, err_ip;
const uint32_t sizebuff = 65535 - (20 + 8);
unsigned char *buff = (unsigned char *) malloc(sizebuff);
struct sockaddr_in servaddr, cliaddr;
struct in_addr serv_in_addr;
struct ip_mreq req;

port = str2uint16(cmdsrv->ipport);
bzero(buff, (size_t)sizebuff);
bzero(&servaddr, sizeof(servaddr));
bzero(&serv_in_addr, sizeof(serv_in_addr));
err_ip = inet_aton(cmdsrv->ipaddr, &serv_in_addr);

if(( err_ip != 0 ) && ( port != 0 )) {
   servaddr.sin_family = AF_INET;
   servaddr.sin_addr = serv_in_addr;
   servaddr.sin_port = htons(port);
   memcpy(&req.imr_multiaddr,&serv_in_addr,sizeof(req.imr_multiaddr));
   req.imr_interface.s_addr = INADDR_ANY;
   sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

   if( sockfd == -1 ) {
      int outerror = errno;
      char *retstr = "Couldn't open socket\n";
      pthread_exit(retstr);
   }
   else {
      struct in_addr ifaddr;
      ifaddr.s_addr = INADDR_ANY;
      int optres3 =
         setsockopt( sockfd, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
                     sizeof( ifaddr ));
      if( optres3 == -1 ) {
         int perrno = errno;
         char *retstr = "Can't set IP_MULTICAST_IF for socket\n";
         printf( "Error setsockopt: ERRNO = %s\n", strerror( perrno ));
         printf( "%s",retstr );
         pthread_exit(retstr);
      }

      unsigned char ttl = 32;
      int optres2 =
         setsockopt( sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
                     sizeof( ttl ));
      if( optres2 == -1 ) {
         int perrno = errno;
         char *retstr = "Can't set IP_MULTICAST_TTL for socket\n";
         printf("Error setsockopt: ERRNO = %s\n",strerror(perrno));
         printf("%s",retstr);
         pthread_exit(retstr);
      }

      int optres =
         setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req,
                     sizeof( req ));
      if( optres == -1 ) {
         int perrno = errno;
         char *retstr = "Can't join to multicast-group\n";
         printf("Error setsockopt: ERRNO = %s\n",strerror(perrno));
         printf("%s",retstr);
         pthread_exit(retstr);
      }

      // Bind port with socket
      uint16_t cliport;
      cliaddr.sin_family = AF_INET;
      cliaddr.sin_addr.s_addr = INADDR_ANY;

      if( strcmp( cmdsrv->ipport, "16011" ) == 0 ) {
         cliport = str2uint16("16003");
         cliaddr.sin_port = htons(cliport);
      }
      else if( strcmp( cmdsrv->ipport, "16012" ) == 0 ) {
         cliport = str2uint16("16004");
         cliaddr.sin_port = htons(cliport);                     
      }
      else {
         printf("Device hasn't such port");
         pthread_exit(NULL);
      }

      int bindres =
         bind( sockfd, (struct sockaddr*)&cliaddr, sizeof( cliaddr ));
      if( bindres == -1 ) {
         int perrno = errno;
         perror("Error in bind\n");
      }
      // ADD 1 BYTE
      data rawdata;
      rawdata.desc = 23;
      printf( "SIZEOF = %d\n", sizeof( *( cmdsrv->cmd )));
      memcpy( &rawdata.cmd, cmdsrv->cmd, sizeof( *( cmdsrv->cmd )));
      printf( "RAWDATA: desc = %d, cmd = %d\n", rawdata.desc, rawdata.cmd );

      int outerror = 0;
      printf( "Send command to IP:\n addr = %s, port = %d\n",
         inet_ntoa( servaddr.sin_addr ), ntohs( servaddr.sin_port ));
      int size = sendto( sockfd, &rawdata, sizeof( rawdata ), 0,
         (struct sockaddr*)&servaddr, sizeof( servaddr ));
      if( size == -1 ) {
         perror("Can't send command to socket");
      }
      ...

有时程序执行成功(此时我有IP -192.168.80.122)。我可以通过wireshark捕获我的多播数据报。
但如果我将IP更改为192.168.1.2,则调用时会出现错误

int optres =
   setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req,
               sizeof( req ));

我甚至不能捕获我的多播数据包。什么也没发送。bug在哪里?

hm2xizp9

hm2xizp91#

如果它对一个IP有效,但对另一个IP无效,也许这能有所帮助。

“IP_ADD_MEMBERSHIP:无此类装置”是指?

这意味着该工具正在尝试使用多播,但网络接口不支持它。可能的原因有两个:

  • 您的机器没有启用多播支持。例如,在Linux和FreeBSD上,编译不支持多播的内核是可能的。
  • 您没有多播流量的路由。有些系统默认不添加此路由,您需要运行. route add -net 224.0.0.0 netmask 224.0.0.0 eth0(或类似程序)。如果您只希望在单播模式下使用RAT,可以在环回接口上添加多播路由。
oxcyiej7

oxcyiej72#

IP_ADD_MEMBERSHIPbind()仅是接收多播所需的,而使用IP_MULTICAST_IF来有效地实现多播组的“仅发送成员资格”。
IP_MULTICAST_IF将内核设置为在给定接口上发送给定组的多播数据包,这实际上是“仅发送”,因为设置后您将无法在该组上接收流量。Posix平台通常以这种方式作为优化,而Win32将执行软件级路由以传播本地生成的数据包。

vm0i2vca

vm0i2vca3#

不能将接口地址用作INADDR_ANY。
请求.imr_接口.s_地址=输入地址_任何;
使用ifconfig检查环回运行的位置。

lo    Link encap:Local Loopback
      inet addr:127.0.0.1  Mask:255.0.0.0
      inet6 addr: ::1/128 Scope:Host
      UP LOOPBACK RUNNING  MTU:65536  Metric:1

您需要使用接口地址作为inet地址,即127.0.0.1
检查环回接口地址并仅使用该地址。

nfeuvbwi

nfeuvbwi4#

请重新检查网络掩码,ip和网关需要在同一个网络.

相关问题