【问题标题】:socket binding with INADDR_ANY and specific interface in multicast with multiple interface与 INADDR_ANY 的套接字绑定和具有多个接口的多播中的特定接口
【发布时间】:2023-03-28 15:30:01
【问题描述】:

我正在尝试编写多播服务器。我有两个问题:

  1. 如何在以太网/wifi 接口等多个接口上发送多播公告。我需要为每个接口创建多个套接字并绑定吗?

  2. 当使用 INADDR_ANY 地址绑定套接字时,描述符已准备好执行 I/O 操作(使用 select 调用)但是当我与特定接口地址(例如以太网/wifi)绑定时,描述符尚未准备好执行任何操作,它卡在 select仅限 api。 那么将套接字与默认地址(INADDR_ANY)或特定接口地址绑定有什么区别?

    int sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sd < 0) {
            printf("scoket() failed");
            return sd;
    }
    
    int r = -1;
    
    int on = 1;
    if ((r = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on))) < 0) {
            printf("recv setsockopt(SO_REUSEADDR) failed");
            return r;
    }
    // add membership to receiving socket
    struct ip_mreq mreq;
    memset(&mreq, 0, sizeof(struct ip_mreq));
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    mreq.imr_multiaddr.s_addr = inet_addr(MDNS_ADDR);
    if ((r = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq))) < 0) {
            printf("recv setsockopt(IP_ADD_MEM) failed");
            return r;
    }
     // enable loopback in case someone else needs the data
    if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &on, sizeof(on))) < 0) {
            printf("recv setsockopt(IP_MULTICAST_LOOP) failed");
            return r;
    }
    
    
    #ifdef IP_PKTINFO
    if ((r = setsockopt(sd, SOL_IP, IP_PKTINFO, (char *) &on, sizeof(on))) < 0) {
            printf("recv setsockopt(IP_PKTINFO) failed");
            return r;
    }
    #endif
    /* bind to an address */
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(MDNS_PORT);
    //serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);       /* receive multicast */
    serveraddr.sin_addr.s_addr = inet_addr("192.168.10.23");        /* receive multicast */
    if ((r = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0) {
            printf("recv bind()");
    }
    

在线程中等待描述符为 I/O 做好准备(基本上都是读取文件描述符)

            FD_ZERO(&sockfd_set);
            FD_SET(svr->sockfd, &sockfd_set);
            FD_SET(svr->notify_pipe[0], &sockfd_set);
            printf("before select\n");
            select(max_fd + 1, &sockfd_set, NULL, NULL, NULL);
            printf("after select\n");

当套接字 id 与 INADD_ANY 地址绑定时,select 将返回,并且我可以使用文件描述符进行读取,但是当与特定接口绑定时,select 永远不会返回,因为没有可读取的文件描述符。

【问题讨论】:

  • 当你绑定到INADDR_ANY,然后调用select,你检查select返回什么?并检查sockfd_set 中设置了哪些描述符?谈到错误,是否任何系统调用都失败了,你真的应该打印the error(也许在strerror的帮助下)。
  • 我已将套接字描述符添加到 sockfd_set 和 select 将在与 INADDR_ANY 绑定时返回 1,之后我使用 FD_ISSET 检查套接字描述符并对特定描述符执行读取操作。在其他情况下,选择根本没有返回,因为我没有提到超时。
  • 接收多播时,始终绑定到INADDR_ANY。在 Linux 中,如果绑定到特定接口,将无法接收多播。

标签: c sockets networking udp multicast


【解决方案1】:

将套接字与特定地址绑定是一种将其锁定到设备的通用方法。这种方法有点过时,因为可以在程序启动后在设备上更改地址。一般来说,我建议绑定到 INADDR_ANY。

您可以随时更改套接字上的输出多播设备。

考虑的选项:

人 7 ip :
IP_MULTICAST_ALL - 传送到所有设备(默认 1)
IP_MULTICAST_IF - 我很确定这只会设置输出设备

人 7 插座:
SO_BINDTODEVICE

稍微玩一下选项,看看结果如何

【讨论】:

  • IP_MULTICAST_IF 设置为套接字发送相关 IGMP 消息的接口。没有别的了。
【解决方案2】:
  1. 如何在以太网/wifi 接口等多个接口上发送多播公告。我需要为每个接口创建多个套接字并绑定吗?

没有。遍历网络接口并依次调用setsockopt(),并为每个接口使用适当的连接参数。你只需要一个插座。

  1. 使用 INADDR_ANY 地址绑定套接字时,描述符已准备好执行 I/O 操作(使用 select 调用)

这是不正确的。您的代码仅检查可读性。

但是当我绑定特定的接口地址时,例如 ethernet/wifi 然后描述符还没有准备好执行任何操作

这又是不正确的。您只检查可读性,而不是“任何操作”。这意味着没有多播通过您绑定的地址进入。

它只停留在选择 api 上。那么绑定默认地址(INADDR_ANY)或特定接口地址的socket有什么区别呢?

它决定了您发送和接收的 IP 地址。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-10
    • 1970-01-01
    • 2016-10-23
    • 1970-01-01
    • 1970-01-01
    • 2011-08-31
    • 1970-01-01
    • 2012-01-25
    相关资源
    最近更新 更多