如何处理广播消息?

How to handle broadcast messages?

我创建了一个通过本地网络发送广播消息的客户端:

#define SERVER_PORT "7777"

int main(int argc, char** argv)
{
    int sockfd;
    struct addrinfo hints, *servinfo, *p;
    int rv;
    int numbytes;

    if (argc != 3) {
        fprintf(stderr,"usage: client ip message\n");
        exit(1);
    }

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;

    if ((rv = getaddrinfo(argv[1], SERVER_PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    for(p = servinfo; p != NULL; p = p->ai_next) 
    {
        if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
        {
            perror("talker: socket");
            continue;
        }
        break;
    }

    int broadcast = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) == -1)
    {
        perror("setsockopt (SO_BROADCAST)");
        exit(1);
    }

    if (p == NULL) {
        fprintf(stderr, "talker: failed to bind socket\n");
        return 2;
    }

    std::cout << "type any number to start: ";
    int temp = 0;
    std::cin >> temp;

    while(1)
    {
        if ((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, p->ai_addr, p->ai_addrlen)) == -1) 
        {
            std::cout << "[ERROR] sendto error: " << errno << std::endl;
            continue;
        }
        std::cout << "[INFO] sended: " << numbytes << " bytes!" << std::endl;
        sleep(5);
    }

    freeaddrinfo(servinfo);
    close(sockfd);

    return 0;
}

是的,我正在使用没有机会退出的 while(1) 循环(这无关紧要)。

此客户端成功发送广播消息。但是如何从服务器端处理它们呢?我试着用下一种方法来做(服务器被写成 class。这是主要方法):

        virtual void Init() override
        {
            addrinfo hints;
            memset(&hints, 0, sizeof(hints));
            hints.ai_family = AF_INET;
            hints.ai_socktype = SOCK_DGRAM;
            
            int iRes = -1;
            if((iRes = getaddrinfo(m_sIpAddress.c_str(), std::to_string(m_iPort).c_str(), &hints, &m_pAddr)) != 0)
            {
                std::cout << "getaddrinfo error: " << gai_strerror(iRes) << std::endl;
                exit(-1);
            }
            std::cout << "getaddrinfo success!" << std::endl;

            m_iSocket = socket(AF_INET, SOCK_DGRAM, 0);
            if(m_iSocket == -1)
            {
                std::cout << "socket error: " << errno << std::endl;
                exit(-1);
            }
            std::cout << "socket created!" << std::endl;

            if((iRes = bind(m_iSocket, m_pAddr->ai_addr, m_pAddr->ai_addrlen)) == -1)
            {
                std::cout << "bind error: " << errno << std::endl;
                exit(-1);
            }
            std::cout << "binded successfully!" << std::endl;

        }

        virtual void Listen() override
        {
            int iNumOfReadBytes = -1;
            std::string msg;
            msg.resize(1024);

            sockaddr_in clientAddr;
            socklen_t addrLen = sizeof(sockaddr);

            while(true)
            {
                if((iNumOfReadBytes = recvfrom(m_iSocket, const_cast<char*>(msg.c_str()), 1024-1, 0, reinterpret_cast<sockaddr*>(&clientAddr), &addrLen)) == -1)
                {
                    std::cout << "recvfrom error: " << errno << std::endl;
                    continue;
                }

                char ip[16]; //string for ip 
                inet_ntop(AF_INET, &(clientAddr.sin_addr), ip, 16);

                std::cout << "[";
                for (int i = 0; i < 16; i++)
                {
                    std::cout << ip[i];
                }
                std::cout << "]";

                std::cout << msg << std::endl;
            }           
        }

init方法负责socket的初始化,Listen方法负责处理广播消息。

假设服务器有 192.168.88.123 IP 地址,而客户端在 192.168.88.255 上发送广播消息 ip.Server 我想应该从客​​户端接收消息,但它从未真正收到它们。

我也试过配置客户端发送消息到255.255.255.255 ip。消息已发送,但服务器未收到。

那么是代码的错吗?或者有 IP 的东西(如果是这样,那就很奇怪了)?

P.S。我阅读了 Beej 的网络指南。有一个广播示例,但仅来自客户端。但我对从服务器端处理此类消息很感兴趣。

谢谢!

代码看起来不错(不过,有些地方我建议进行调整,比如在调用 getaddrinfo() 时指定 IPPROTO_UDP 协议,并在服务器上包含 AI_PASSIVE 标志侧)。

默认情况下,并非所有网络路由器都允许 UDP 广播。因此,请检查您的路由器配置以及 OS 防火墙。使用数据包嗅探器(如 WireShark)来确保数据包实际上离开了发送方的 NIC 并到达了接收方的 NIC,确保它们在传输过程中没有被阻塞。

此外,仔细检查以确保您的客户端套接字和服务器套接字绑定到同一子网,并且客户端发送到该子网的正确广播 IP。给定 192.168.88.123 的服务器 IP,仅当子网掩码为 255.255.255.0 时,广播 IP 才为 192.168.88.255,您的环境是否如此?

此外,如果您的服务器绑定到 0.0.0.0(侦听所有本地 NIC)而不是绑定到 192.168.88.123(仅侦听 1 个 NIC),请检查您是否遇到同样的问题。