1

我是 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 ,但仍然无法使其正常工作。 通过 UDP 接收来自 N 个客户端的响应,以响应广播请求

编码:

#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();
}
4

1 回答 1

3

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

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

更改MSG_PEEK0,然后每个呼叫将读取尚未读取的第一条消息。(所以第二个调用将读取第二个消息,依此类推)

于 2018-02-02T03:31:50.707 回答