无法显示本地网络 C++ 中的所有 UPnP 设备

Unable to show all UPnP devices within the local network C++

我是 UPnP 开发的新手,正在尝试发现本地网络中的所有 UPnP 设备,我遵循了在线资源中的示例,但我的代码只会在第一次响应时不断循环。我怎么能得到第一个以外的其他回应,我能得到一些提示吗?

示例:

来自 192.168.xxx.123 的 First Response,它会继续打印以下结果:

HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1790
DATE: Thu, 01 Jan 2015 10:43:15 GMT
ST: uuid:4d696xxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
USN: uuid:4d696xxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
EXT:
SERVER: Linux 2.6 DLNADOC/1.50 UPnP/1.0 ReadyDLNA/1.0.26
LOCATION: http://192.168.xxx.123:xxxx/rootDesc.xml
Content-Length: 0

我检查了 Wireshark,我可以看到另一个设备 [IP: 192.168.xxx.99] 已经给了我一个响应,但我无法在我的代码中接收到它。

我还阅读了一个关于 SO 的问题并在我的代码中使用了 select,但仍然无法正常工作。 Receiving response(s) from N number of clients in reply to a broadcast request over UDP

代码:

#include <QCoreApplication>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>

#define RESPONSE_BUFFER_LEN 1024
#define SSDP_MULTICAST "239.255.255.250"
#define SSDP_PORT 1900

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int sock;
    size_t ret;
    unsigned int socklen;
    struct sockaddr_in sockname;
    struct sockaddr clientsock;
    struct hostent *hostname;
    char data[] =
        "M-SEARCH * HTTP/1.1\r\n"
        "HOST: 239.255.255.250:1900\r\n"
        "MAN: \"ssdp:discover\"\r\n"
        "ST: ssdp:all\r\n"
        "MX: 120\r\n"
        "\r\n";
    char buffer[RESPONSE_BUFFER_LEN];
    unsigned int len = RESPONSE_BUFFER_LEN;
    fd_set fds;
    struct timeval timeout;

    hostname = gethostbyname(SSDP_MULTICAST);
    hostname->h_addrtype = AF_INET;

    if((sock = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("err: socket() failed");
        return -1;
    }

    memset((char *)&sockname, 0, sizeof(struct sockaddr_in));
    sockname.sin_family = AF_INET;
    sockname.sin_port = htons(SSDP_PORT);
    sockname.sin_addr.s_addr = *((unsigned long *)(hostname->h_addr_list[0]));

    ret = sendto(sock, data, strlen(data), 0, (struct sockaddr *)&sockname,
                 sizeof(struct sockaddr_in));
    if(ret != strlen(data))
    {
        printf("err:sendto");
        return -1;
    }

    /* Get response */
    FD_ZERO(&fds);
    FD_SET(sock, &fds);
    timeout.tv_sec = 5;
    timeout.tv_usec = 5;
    while(select(sock + 1, &fds, NULL, NULL, &timeout) > 0)
    {
        if(FD_ISSET(sock, &fds))
        {
            socklen = sizeof(clientsock);
            if((len = recvfrom(sock, buffer, len, MSG_PEEK, &clientsock, &socklen)) == (size_t)-1)
            {
                printf("err: recvfrom");
                return -1;
            }

            buffer[len] = '[=11=]';

            /* Check the HTTP response code */
            if(strncmp(buffer, "HTTP/1.1 200 OK", 12) != 0)
            {
                printf("err: ssdp parsing ");
                return -1;
            }
            printf(buffer);
        }
        else
        {
            printf("err: no ssdp answer");
        }
    }
    //close(sock);
    return a.exec();
}

您正在使用 MSG_PEEK,这意味着读取套接字接收缓冲区中的第一条消息,但不会将其从缓冲区中移除。

因此,每次调用 recvfrom 时,您都会收到第一条消息。

MSG_PEEK更改为0,然后每次调用都会读取尚未读取的第一条消息。 (因此第二次调用将读取第二条消息,依此类推)