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

时间:2018-02-02 00:52:15

标签: c linux sockets upnp ssdp

我是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();
}

1 个答案:

答案 0 :(得分:3)

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

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

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