【问题标题】:Unable to show all UPnP devices within the local network C++无法显示本地网络 C++ 中的所有 UPnP 设备
【发布时间】:2018-02-02 00:52:15
【问题描述】:

我是 UPnP 开发的新手,并试图发现本地网络中的所有 UPnP 设备,我遵循了在线资源中的一个示例,但我的代码只会在第一个响应时保持循环。除了第一个之外,我怎么能得到另一个回应,我能得到一些提示吗?

例子:

来自 192.168.xxx.123 的第一个响应,它将继续打印以下结果:

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] = '\0';

            /* 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();
}

【问题讨论】:

  • 在增加 sock 之后,它不会得到响应并且不会打印任何输出。将尝试逐步完成。
  • 除了您对QCoreApplication a(argc, argv);return a.exec(); 的调用(它们都与您的代码无关)之外,您的代码是C,而不是C++。您可能需要更改标签。
  • 由于数据类型范围有限,您的(len = recvfrom(sock, buffer, len, MSG_PEEK, &amp;clientsock, &amp;socklen)) == (size_t)-1 比较总是错误的。 len 应该是 ssize_t

标签: c linux sockets upnp ssdp


【解决方案1】:

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

因此,每次您拨打recvfrom 时,您都会收到第一条收到的消息。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-23
    相关资源
    最近更新 更多