You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何启用IP_MULTICAST_LOOP后仅在eth0接收自播组播包?

组播单套接字收发时仅收到eth0数据包的问题分析

我用C写了一个组播程序,同一个套接字既负责发送组播包,又在所有接口上订阅了目标组播组。按预期,发送端应该收到自己发出的数据包,且loopback和eth0接口各收到一次,但实际仅在eth0接口收到数据包。IP_MULTICAST_LOOP默认处于启用状态,相关代码如下:

#define MULTICAST_PORT 1112
#define MULTICAST_GROUP "239.0.0.1"

int create_multi_receiver()
{
    // Send is also through this socket
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in in_servaddr;
    struct ip_mreq mreq;
    // Bind UDP server
    bzero(&in_servaddr, sizeof(in_servaddr));
    in_servaddr.sin_family = AF_INET;
    in_servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    in_servaddr.sin_port = htons(MULTICAST_PORT);
    if (bind(fd, (struct sockaddr *)&in_servaddr, sizeof(in_servaddr)) == -1)
        error_exit("bind error in UDP");

    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);

    if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
        error_exit("setsockopt");

    int opt = 1;
    if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) < 0)
        error_exit("setsockfd");

    return fd;
}

struct msg *recv_multi_msg(int udpfd)
{
    struct msg nmb_msg;     /* space to msg into */
    struct iovec vector[1]; /* file name from the child */
    struct msghdr msg;      /* full message */
    struct cmsghdr *cmsg;   /* control message with the fd */

    /* set up the iovec for the file name */
    vector[0].iov_base = &nmb_msg;
    vector[0].iov_len = sizeof(nmb_msg);

    /* the message we're expecting to receive */
    memset(&msg, 0, sizeof(msg));
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = vector;
    msg.msg_iovlen = 1;

    /* overprovisioning buffer for now */
    char cmbuf[128];
    msg.msg_control = cmbuf;
    msg.msg_controllen = sizeof(cmbuf);
    printf("Receiving message..\n");
    if (recvmsg(udpfd, &msg, 0) == -1)
    {
        perror("recvmsg multireceiver");
        return NULL;
    }
    printf("received message..\n");
    // TODO: Test this part, very high chance of error
    for ( // iterate through all the control headers
        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
        cmsg != NULL;
        cmsg = CMSG_NXTHDR(&msg, cmsg))
    {
        // ignore the control headers that don't match what we want
        if (cmsg->cmsg_level != IPPROTO_IP ||
            cmsg->cmsg_type != IP_PKTINFO)
        {
            continue;
        }
        struct in_pktinfo pi;
        memcpy(&pi, CMSG_DATA(cmsg), sizeof(pi));
        printf("Destination IP: %s\n", inet_ntoa(pi.ipi_spec_dst));
        // in_addr_t ip = (nmb_msg.mtype) >> 16;
        // if (pi.ipi_spec_dst.s_addr != ip)
        //     return NULL;

        // break;
    }
    return NULL;

        // Do some stuff later 
}



void send_multi_msg(int udpfd, int udsfd)
{
    struct msg msg;
    if (recv(udsfd, &msg, sizeof(msg), 0) > 0)
    {
        struct sockaddr_in addr;
        int alen;
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(MULTICAST_GROUP);
        addr.sin_port = htons(MULTICAST_PORT);
        alen = sizeof(addr);
        printf("sending %s\n", msg.mtext);
        if (sendto(udpfd, &msg, sizeof(msg), 0, (struct sockaddr *)&addr, alen) == -1)
            perror("sendto in multicast");
    }
}

问题根源

  • 组播发送的出口接口默认选择逻辑
    调用sendto发送组播包时,系统会自动选择路由表中默认网关对应的接口(即你的eth0)作为唯一出口,不会同时在所有接口发送数据包。因此实际只有eth0接口发出了组播包,自然只有该接口能收到回环的数据包。
  • IP_ADD_MEMBERSHIP的作用边界
    用INADDR_ANY添加组播成员资格,只会让系统在所有接口上开启组播接收能力,但不会改变发送操作的出口接口选择逻辑,发送的组播包仍然只会从单一接口出去。
  • 回环接口的包生成条件
    只有当组播包从回环接口(lo)发出时,才会在回环接口生成可被接收的回环包。你的发送操作未指定lo作为出口,因此不会有包从lo接口发出,自然也收不到该接口的回环包。

解决办法

如果需要在多个接口都收到回环包,需要针对每个接口单独发送组播包,并通过IP_MULTICAST_IF指定对应出口:

// 示例:指定回环接口发送
struct in_addr if_addr;
if_addr.s_addr = htonl(INADDR_LOOPBACK);
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &if_addr, sizeof(if_addr));
sendto(...); // 此时包从lo接口发出,会触发lo的回环接收

// 再指定eth0接口发送
if_addr.s_addr = inet_addr("你的eth0网卡IP");
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &if_addr, sizeof(if_addr));
sendto(...); // 此时包从eth0发出,触发eth0的回环接收

或者可以创建多个套接字,每个套接字绑定到不同接口并单独发送组播包,这样每个接口都会生成对应的回环包被接收。

内容的提问来源于stack exchange,提问作者pransin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 14:55:20