繁体   English   中英

多播环回发送方套接字

[英]Multicast loopback to sender socket

我正在编写一个多播数据包的 C 程序。 用于多播的同一个套接字订阅了所有接口上的多播组。 这意味着发件人将收到自己的数据包。 我希望套接字接收消息两次,一次在环回接口上,另一次在 eth0 接口上。 这是相同的代码。


#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");
    }
}

但是,我只收到 eth0 数据包。 为什么会这样? IP_MULTICAST_LOOP默认启用。

我尝试检查 StackOverflow,但没有一个问题得到令人满意的回答。

当您使用sendto发送多播数据报时,它只会在单个接口上发送数据包。 所以你只收到一个数据包,因为你只发送一个数据包。

默认情况下, sendto将用于多播的接口通常是系统上的第一个 non-loopback.network 接口。 您可以通过在发送套接字上设置IP_MULTICAST_IF选项来控制使用哪个接口。 因此,如果您想在多个接口上发送,您需要多次调用sendto并在每次发送前设置IP_MULTICAST_IF

您还使用INADDR_ANY作为加入多播组的接口。 这通常也是第一个非环回接口。 如果你运行你的程序,然后当它仍然运行时运行netstat -ng你可以看到哪个接口被加入了。

如果要在多个接口上监听多播,则需要为每个接口设置IP_ADD_MEMBERSHIP选项。

通过网络发送的 IP 个数据包可以分段 receiving.network 堆栈将重新组合片段。 这就是所谓的 IP 重组。

这些片段由 IP 标识符和偏移量标识。 RFC如果您发送一个IP 数据包,它会获得一个标识符。 Your.network 堆栈丢弃所有已收到的“片段”。 因此,您只收到一次数据包,尽管它可能有多个路径到您的网络适配器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM