【问题标题】:C Application not recieving MulticastC 应用程序未接收多播
【发布时间】:2022-01-16 11:41:50
【问题描述】:

我正在尝试创建一个应用程序,它使用多播与本地网络上的应用程序的其他实例通信(应用程序应该在 windows 和 linux 下工作)。

我是多播的新手,所以我尝试使用我在互联网上找到的以下代码:

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#define EXAMPLE_PORT 6000
#define EXAMPLE_GROUP "239.124.0.1"

// If argc == 0, recieve, else send
int main(int argc, char**argv)
{
    struct sockaddr_in addr;
    socklen_t addrlen = 0;
    int sock = 0, cnt = 0;
    struct ip_mreq mreq;
    char message[50];

    /* set up socket */
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        perror("socket");
        exit(1);
    }

    bzero((char *)&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(EXAMPLE_PORT);
    addrlen = sizeof(addr);

    if (argc > 1) {
        /* send */
        addr.sin_addr.s_addr = inet_addr(EXAMPLE_GROUP);
        while (1) {
            time_t t = time(0);
            sprintf(message, "time is %-24.24s", ctime(&t));
            printf("sending: %s\n", message);
            cnt = sendto(sock, message, sizeof(message), 0,
                         (struct sockaddr *) &addr, addrlen);
            if (cnt < 0) {
                perror("sendto");
                exit(1);
            }
            sleep(5);
        }
    } else {
        /* receive */
        if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
            perror("bind");
            exit(1);
        }
        mreq.imr_multiaddr.s_addr = inet_addr(EXAMPLE_GROUP);
        mreq.imr_interface.s_addr = htonl(INADDR_ANY);
        if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                       &mreq, sizeof(mreq)) < 0) {
            perror("setsockopt mreq");
            exit(1);
        }
        while (1) {
            cnt = recvfrom(sock, message, sizeof(message), 0,
                           (struct sockaddr *) &addr, &addrlen);
            if (cnt < 0) {
                perror("recvfrom");
                exit(1);
            } else if (cnt == 0) {
                break;
            }
            printf("%s: message = \"%s\"\n", inet_ntoa(addr.sin_addr), message);
        }
    }
}

代码成功发送了我可以在我的安卓手机上接收到的多播数据包(通过编译完全相同的代码并使用 Termux 编译/执行)。

所以我知道代码正在运行。 但这是我的问题:在 linux 和 windows 上,我无法接收数据包。我可以发送它们(我的手机确实收到了来自两者的数据包),但我无法接收。

令我惊讶的是,它在我的 linux 和 android 上是完全相同的代码(在 windows 上,使用 winsock2 的代码只有一些调整)。

此外,我可以看到我的 linux 确实收到数据包:

$ sudo tcpdump -i wlp58s0 host 239.124.0.1

dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wlp58s0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:36:59.196616 IP 192.168.1.10.48727 > 239.124.0.1.6000: UDP, length 50
12:37:04.112507 IP 192.168.1.10.48727 > 239.124.0.1.6000: UDP, length 50
12:37:09.129963 IP 192.168.1.10.48727 > 239.124.0.1.6000: UDP, length 50
^C
4 packets captured
4 packets received by filter
0 packets dropped by kernel

192.168.1.10 是我在该网络上的手机 IP 地址。

我也可以看到我成功加入了组播组:

$ netstat -gn | grep 239.124.0.1

wlp58s0         1      239.124.0.1

所以我的问题是为什么我不能在 linux/windows 上接收多播数据包?

我需要更改哪些代码才能接收它们?


编辑: 看来如果我禁用我的防火墙sudo systemctl stop firewalld.service 我可以收到数据包。

我真的不想让我的用户禁用他们的防火墙,我该怎么做? (为什么防火墙首先会阻止多播?)

【问题讨论】:

    标签: c linux windows sockets multicast


    【解决方案1】:

    对于接收者,此代码加入接口 0.0.0.0(指定为INADDR_ANY)上的多播组。这意味着它加入了被认为是默认接口的网络接口。如果这不是接收多播流量的同一个接口,您将不会收到数据包。

    您正在接口 wlp58s0 上接收数据包,因此请查看该接口使用的 IP 地址,并在选择要绑定的接口时使用该 IP。

    例如,如果 wlp58s0 的 IP 地址为 192.168.1.2,则更改此:

    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    

    到这里:

    mreq.imr_interface.s_addr = inet_addr("192.168.1.2");
    

    【讨论】:

    • 我试过mreq.imr_interface.s_addr = inet_addr("192.168.1.13");,没有任何改变
    猜你喜欢
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多