UDP 广播和多播消息到达,但 recvfrom 未收到任何内容

发布于 2025-01-16 15:13:29 字数 7755 浏览 3 评论 0原文

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

我的代码是用 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] == '\0')
    {
        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, '\0', 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, '\0', sizeof(sending_message));
    memset(receiving_message, '\0', 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 容器将应用程序部署到系统

I am new to stackoverflow and also pretty much a beginner at programming and hope to find a solution here.

My code is written in C++ and should run on a computer on module with linux operating system. The program should receive messages from other linux or windows systems and then depending on the content of the messages execute further subroutines and send back a response. The windows program is also written in C++. The linux system and the windows system are connected via a switch and the switch is connected to the home network via a powerline adapter. The multicast function is enabled and supported in the switch settings, as well as in the linux system.

The linux code to test the functionality looks like this:

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] == '\0')
    {
        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, '\0', 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, '\0', sizeof(sending_message));
    memset(receiving_message, '\0', 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);
}

If i now send unicast messages to the linux program, everything works as it should and the message is received and the sent values are inserted correct into the printf() functions. Sending unicast messages also works without problems. However, if I want to receive broadcast or multicast messages, the program stops in the recvfrom() line. If I check the connected port with tcpdump port 3300 for incoming messages, they arrive at the linux system. If I try to send broadcast or multicast messages, this does not work and no outgoing messages are displayed in tcpdump.
If I try to receive broadcast or multicast messages and then go back to try again to receive unicast messages, this also does not work anymore. I do not get any error messages during the showed errorchecking.

Thanks in advance for your help.

Edit: Maybe I forgot to mention something because I thought it shouldn't be that big of a deal, but I've also read now that this could be a problem. The application is deployed to the system using a docker container

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

尤怨 2025-01-23 15:13:29

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

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

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

You're not correctly setting the incoming interface for multicast traffic, and you're not setting the outgoing interface at all.

When you call joinMulticastGroup, you pass an empty string for the second argument which is supposed to contain the IP address of the incoming multicast interface as a string. So if for example the machine's IP is 192.168.178.34, then you pass "192.168.178.34" for that argument.

If you don't set the outgoing multicast interface explicitly, the OS will choose whichever interface is the "default". You should use the IP_MULTICAST_IF socket option, passing the address of a struct in_addr specifying the IP address.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文