UDP 广播和多播消息到达但 recvfrom 没有收到任何东西

UDP broadcast and multicast messages arrive but recvfrom does not receive anything

我是 Whosebug 的新手,也是编程的初学者,希望能在这里找到解决方案。

我的代码是用 C++ 编写的,应该 运行 在装有 linux 操作系统模块的计算机上。该程序应该从其他 linux 或 windows 系统接收消息,然后根据消息的内容执行进一步的子程序并发回响应。 windows 程序也是用 C++ 编写的。 linux系统和windows系统通过交换机连接,交换机通过电力线适配器连接到家庭网络。多播功能在开关设置和linux系统中被启用和支持。

用于测试功能的 linux 代码如下所示:

int createIPv4MulticastSocket(uint16_t socket_port, int allowReuseAddress)
{
    int Socket;
    int broadcast = 1;
    sockaddr_in localSock = {};

    // Bind to the proper port number with the IP address specified as INADDR_ANY
    memset(&localSock, 0, sizeof(localSock));
    localSock.sin_family = AF_INET;
    localSock.sin_port = htons(socket_port);
    localSock.sin_addr.s_addr = INADDR_ANY;

    // Creating the Socket
    printf("Creating a socket...");
    if ((Socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("Creating a socket failed:");
        printf("\n");
    }
    else
    {
        printf("Socket created. \n");
    }

    // set the reuse address options
    if (setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, (char*)&allowReuseAddress, sizeof(allowReuseAddress)) < 0)
    {
        perror("Error setting the reuse address option");
        printf("\n");
    }
    else
        printf("Setting the reuse address option...OK. \n");


    // bind the socket to the defined address
    printf("Try to bind the created Socket to my address. \n");
    if (bind(Socket, (struct sockaddr*)&localSock, sizeof(localSock)) == -1) {
        perror("Binding socket failed:");
        printf("\n");
    }
    else
    {
        printf("Bind was succesful. \n");
    }

    // sets the socket options so you can send Broadcast messages
    printf("Setting the socket options to allow Broadcast. \n");
    if (setsockopt(Socket, SOL_SOCKET, SO_BROADCAST, &broadcast,
        sizeof(broadcast)) == -1) {
        perror("Setting the socket options for allowing broadcast failed:");
        printf("\n");
    }
    else
    {
        printf("Setting the broadcast options...OK. \n");
    }

    return Socket;
}


void joinMulticastGroup(const char* IPMulticastGroup, const char* IPLocalInterfaceAddr, int SocketDescriptor)
{
    struct ip_mreq group;
    int LocalIP;
    int conv_ip;

    if (IPLocalInterfaceAddr[0] == '[=10=]')
    {
        conv_ip = inet_pton(AF_INET, IPMulticastGroup, &group.imr_multiaddr.s_addr);
        if (conv_ip == 0) {
            printf("Destination IP-address doesn't contain a valid network address in the specified address family.\n");
        }
        else if (conv_ip == -1) {
            perror("No valid address family:");
            printf("\n");
        }

        group.imr_interface.s_addr = htonl(INADDR_ANY);
    }
    else
    {
        conv_ip = inet_pton(AF_INET, IPMulticastGroup, &group.imr_multiaddr.s_addr);
        if (conv_ip == 0) {
            printf("Destination IP-address doesn't contain a valid network address in the specified address family.\n");
        }
        else if (conv_ip == -1) {
            perror("No valid address family:");
            printf("\n");
        }

        conv_ip = inet_pton(AF_INET, IPLocalInterfaceAddr, &group.imr_interface.s_addr);
        if (conv_ip == 0) {
            printf("Destination IP-address doesn't contain a valid network address in the specified address family.\n");
        }
        else if (conv_ip == -1) {
            perror("No valid address family:");
            printf("\n");
        }
    }

    if (setsockopt(SocketDescriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&group, sizeof(group)) < 0)
    {
        perror("Adding multicast group error");
        printf("\n");
    }
    else
        printf("Adding multicast group...OK. \n");
}


void sendUDP(int sending_socket, const char* destination_ipaddress,
    uint16_t destination_port, unsigned char sending_message[], int size_of_sending_message)
{
    struct sockaddr_in destination_address;
    long int numbytes_send;
    int conv_ip;

    // define destination address    
    printf("Convert the destination address to sockaddr_in. \n");
    destination_address.sin_family = AF_INET;                            // IPv4 address
    destination_address.sin_port = htons(destination_port);              // destination port
    conv_ip = inet_pton(AF_INET, destination_ipaddress, &destination_address.sin_addr.s_addr);
    if (conv_ip == 0) {
        printf("Destination IP-address doesn't contain a valid network address in the specified address family.\n");
    }
    else if (conv_ip == -1) {
        perror("No valid address family:");
        printf("\n");
    }
    memset(destination_address.sin_zero, '[=10=]', sizeof(destination_address.sin_zero));  // fill up sin_zero with "0"
    printf("Correct destination address sockaddr. \n");

    printf("Sending a message...");
    if ((numbytes_send = sendto(sending_socket, sending_message, size_of_sending_message, 0,
        (struct sockaddr*)&destination_address, sizeof(destination_address))) == -1) {
        perror("sendto() failed:");
        printf("\n");
    }
    else
    {
        printf(" %i Bytes of data have been sent. \n", numbytes_send);
    }
}


void receiveUDP(int receiving_socket, struct sockaddr* received_from,
    unsigned char receiving_message[], int size_of_receiving_message)
{
    long int numbytes_received;
    unsigned int len_received_from = sizeof(*received_from);
    socklen_t len_recv_from = len_received_from;

    printf("Trying to receive a message...");
    if ((numbytes_received = recvfrom(receiving_socket, receiving_message, size_of_receiving_message, 0,
        received_from, &len_recv_from)) == -1) {
        perror("Receiving message failed:");
        printf("\n");
    }
    else
    {
        printf("%i Bytes an Daten erhalten\n", numbytes_received);
    }
}


int main()
{
    struct sockaddr received_from;
    int socketfd;
    unsigned char sending_message[1472], receiving_message[1472];
    const char* destination_ipaddress = "192.168.178.35";   //Laptop
    const char* multicast_ipaddress = "224.0.1.14";         //Multicast
    const char* broadcast_ipaddress = "192.168.178.255";    //Broadcast
    uint16_t destination_port = 3300;
    uint16_t port = 3300;
    uint16_t messageid = 0;
    double altitude = 0;
    double longitude = 0;
    double lattitude = 0;

    // Clean message buffer
    memset(sending_message, '[=10=]', sizeof(sending_message));
    memset(receiving_message, '[=10=]', sizeof(receiving_message));

    // Create a Socket
    socketfd = createIPv4MulticastSocket(port, 1);

    // join the multicast group
    joinMulticastGroup(multicast_ipaddress, "", socketfd);

    // Send UDP message.
    sendUDP(socketfd, broadcast_ipaddress, destination_port, sending_message, sizeof(sending_message));


    

    /// Receive messages and read Data
    while (1)
    {
        receiveUDP(socketfd, &received_from, receiving_message, sizeof(receiving_message));
        
        messageid = unpackunsignedint16(receiving_message, 1);
        altitude = unpackdouble(receiving_message, 3);
        lattitude = unpackdouble(receiving_message, 11);
        longitude = unpackdouble(receiving_message, 19);

        printf("actual altitude is: %lf \n", altitude);
        printf("actual lattitude is: %lf \n", lattitude);
        printf("actual longitude is: %lf \n", longitude);
    }

    close(socketfd);
}

如果我现在向 linux 程序发送单播消息,一切正常,消息被接收并且发送的值被正确插入到 printf() 函数中。发送单播消息也没有问题。但是,如果我想接收广播或多播消息,程序会在 recvfrom() 行停止。如果我使用 tcpdump 端口 3300 检查连接的端口是否有传入消息,它们会到达 linux 系统。如果我尝试发送广播或多播消息,这将不起作用,并且 tcpdump 中不会显示任何传出消息。 如果我尝试接收广播或多播消息然后返回再次尝试接收单播消息,这也不再有效。在显示的错误检查期间我没有收到任何错误消息。

在此先感谢您的帮助。

编辑:也许我忘了提及一些事情,因为我认为这没什么大不了的,但我现在也读到这可能是个问题。使用 docker 容器

将应用程序部署到系统

您没有正确设置多播流量的传入接口,而且您根本没有设置传出接口。

当您调用 joinMulticastGroup 时,您为第二个参数传递了一个空字符串,该参数应该包含作为字符串的传入多播接口的 IP 地址。因此,例如,如果机器的 IP 是 192.168.178.34,那么您为该参数传递“192.168.178.34”。

如果您没有明确设置传出多播接口,OS 将选择“默认”接口。您应该使用 IP_MULTICAST_IF 套接字选项,传递指定 IP 地址的 struct in_addr 地址。