【问题标题】:UDP broadcast via sendto() returns "Can't assign requested address" on OS/X but not Linux通过 sendto() 进行的 UDP 广播在 OS/X 而不是 Linux 上返回“无法分配请求的地址”
【发布时间】:2016-01-09 09:37:41
【问题描述】:

我正在尝试使用 sendto() 函数通过 UDP 广播字符串。

以下代码在 Linux 机器(例如 Raspberry Pi)上运行良好,但在 iMac 和 MacBook Air 上的 OS/X 下失败。

#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

int main(int argc, char*argv[])
{
  const char *msg_str = "hello, world";
  const char *bcast_addr = argv[1];
  int port = atoi(argv[2]);
  struct sockaddr_in sock_in;
  int yes = 1;
  int sinlen = sizeof(struct sockaddr_in);
  memset(&sock_in, 0, sinlen);
  int sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  if ( sock < 0 ) {
    printf("socket: %d %s\n", errno, strerror(errno));
    exit(-1);
  }

  sock_in.sin_addr.s_addr=inet_addr(bcast_addr);  
  sock_in.sin_port = htons(port);
  sock_in.sin_family = PF_INET;

  if ( bind(sock, (struct sockaddr *)&sock_in, sinlen) < 0 ) { 
    printf("bind: %s %d %s\n", bcast_addr, errno, strerror(errno));
    exit(-1);
  }

  if ( setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(int) ) < 0 ) { 
    printf("setsockopt: %d %s\n", errno, strerror(errno));
    exit(-1);
  }

  if  ( sendto(sock, msg_str, strlen(msg_str), 0, (struct sockaddr *)&sock_in, sinlen) < 0 ) {
    printf("sendto: %d %s str='%s', sinlen=%d\n", errno, strerror(errno), msg_str, sinlen);
    exit(-1);
  }
  printf("message sent!\n");
}

我的 OS/X 机器位于本地网络上,IP 地址为 192.168.0.4,广播地址为 192.168.0.255ifconfig en1 | grep broadcast 的输出产生以下内容:

inet 192.168.0.4 netmask 0xffffff00 broadcast 192.168.0.255

如果我像这样运行上面的代码:

a.out 192.168.0.255 1234

bind()setsockopt() 函数有效,但 sendto() 返回 errno 49。我的程序打印以下内容:

sendto: 49 Can't assign requested address str='hello, world', sinlen=16

但如果我这样运行:

a.out 192.168.0.4 1234

然后一切正常。但当然广播只会发送到本地盒子。

当我在同一网络上的 Linux 机器上使用广播地址(例如 192.168.0.255)时,它工作正常。在我的 Mac 上,我尝试以普通用户和 root 用户身份运行,结果相同。我似乎记得这工作在几个版本的 OS/X 之前(我知道它在 Mavericks 上不起作用)。

知道苹果在这里做什么吗?

【问题讨论】:

    标签: linux macos sockets udp


    【解决方案1】:

    看起来 linux 的限制较少。问题应该是尝试绑定到非本地地址 192.168.0.255:

    sock_in.sin_addr.s_addr=inet_addr(bcast_addr);
    

    为什么不使用 0.0.0.0 或 127.0.0.1 作为源地址? 或者,如果您只想绑定到特定接口,您可以使用例如处理有关网络地址和网络掩码的信息。 getifaddrs/freeifaddrs。

    【讨论】:

      【解决方案2】:

      我需要地址 192.168.0.255,因为我希望在整个本地子网中广播消息。

      但我y_ug 是对的——问题在于在非本地地址上调用bind()。我根本不需要那个电话,因为我所做的只是发送。事实上,这毫无意义——我一定是从其他代码中复制了它。出于某种原因,Raspberry Pi(运行 Debian Linux)似乎并不介意并且工作正常。但是 OS/X 框给出了上面的错误。

      【讨论】:

        【解决方案3】:

        UDP 通道处于较高范围内。从 224.0.0.1 到 239.255.255.255 的有效多播范围地址——所以我很惊讶你的程序能正常工作。

        【讨论】:

          猜你喜欢
          • 2015-01-14
          • 2013-08-08
          • 1970-01-01
          • 1970-01-01
          • 2017-02-18
          • 1970-01-01
          • 1970-01-01
          • 2016-05-21
          • 1970-01-01
          相关资源
          最近更新 更多