Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Qt/C++;SSDP发现_C++_Qt_Udp_Ssdp - Fatal编程技术网

C++ Qt/C++;SSDP发现

C++ Qt/C++;SSDP发现,c++,qt,udp,ssdp,C++,Qt,Udp,Ssdp,我正在尝试为sonos扬声器编写一个小型控制器二进制文件。为此,我希望执行SSDP发现 QHostAddress groupAddress = QHostAddress("239.255.255.250"); m_socket = new QUdpSocket(this); auto ok = m_socket->bind(QHostAddress::AnyIPv4, 56123, QUdpSocket::ShareAddress); i

我正在尝试为sonos扬声器编写一个小型控制器二进制文件。为此,我希望执行SSDP发现

   QHostAddress groupAddress = QHostAddress("239.255.255.250");
    m_socket = new QUdpSocket(this);
    auto ok = m_socket->bind(QHostAddress::AnyIPv4, 56123, QUdpSocket::ShareAddress);

    if (!ok)
    {
        return;
    }


    ok = m_socket->joinMulticastGroup(groupAddress);
    if (!ok)
    {
        return;
    }
    QByteArray message("M-SEARCH * HTTP/1.1\r\n"        \
                       "HOST: 239.255.255.250:1900\r\n" \
                       "MAN: \"ssdp:discover\"\r\n" \
                       "MX: 5\r\n" \
                       "ST: urn:smartspeaker-audio:service:SpeakerGroup:1\r\n" \
                       "linux/4.13 UPnP/1.1 myos/0.11.1\r\n" \
                       "\r\n");

    for(int i=0; i<4; i++){
        auto writeOk = m_socket->writeDatagram(message.data(), groupAddress, 1900);

        if (writeOk == -1)
        {
            qDebug() << "Writing Datagram failed";
        }

    }

    while (m_socket->hasPendingDatagrams())
    {
        QByteArray reply;
        reply.resize(m_socket->pendingDatagramSize());
        m_socket->readDatagram(reply.data(), reply.size());
        qDebug() << reply.data();
    }
    qDebug() << "No more pending datagrams";
这里突出的是syscall recv()失败,还有getpeername()。为了验证这不是网络权限问题或类似问题,我编写了一个python脚本:

class SSDPClient:

    def __init__(self):
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    def discover(self, timeout):
        request_content = ("M-SEARCH * HTTP/1.1\n"
                          "HOST: 239.255.255.250:1900\n"
                          "MAN: \"ssdp:discover\"\n"
                          "MX: {duration}\n"
                          "ST: urn:smartspeaker-audio:service:SpeakerGroup:1\n"
                          "USER-AGENT: {osstring} UPnP/1.1 {productstring}\n").format(duration=timeout, osstring="linux/4.13", productstring="myos/0.11.1").encode('utf-8')
        [self._socket.sendto(request_content, ("239.255.255.250", 1900)) for i in range(0,3)]
        self._socket.settimeout(timeout)
        response, address = self._socket.recvfrom(1024)
        print(response)
这个脚本很有效。在上面运行strace:

socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 3
sendto(3, "M-SEARCH * HTTP/1.1\nHOST: 239.25"..., 171, 0, {sa_family=AF_INET, sin_port=htons(1900), sin_addr=inet_addr("239.255.255.250")}, 16) = 171
sendto(3, "M-SEARCH * HTTP/1.1\nHOST: 239.25"..., 171, 0, {sa_family=AF_INET, sin_port=htons(1900), sin_addr=inet_addr("239.255.255.250")}, 16) = 171
sendto(3, "M-SEARCH * HTTP/1.1\nHOST: 239.25"..., 171, 0, {sa_family=AF_INET, sin_port=htons(1900), sin_addr=inet_addr("239.255.255.250")}, 16) = 171
ioctl(3, FIONBIO, [1])                  = 0
clock_gettime(CLOCK_MONOTONIC, {tv_sec=10531, tv_nsec=209135513}) = 0
poll([{fd=3, events=POLLIN}], 1, 3000)  = 1 ([{fd=3, revents=POLLIN}])
让我印象深刻的是,python代码似乎并没有完成所有的
setsockopt
syscalls。
有人能帮我找出使用QUdpSocket的问题吗?我知道如果需要的话,我可以使用原始套接字实现,但是如果我可以让它工作的话,我宁愿使用内置的东西。
hasPendingDatagrams
方法期望事件循环有时间首先接收和处理传入消息


作为一种快速黑客,您可以调用
m_socket->waitForReadyRead()
。这将在有限的时间(30秒)内运行事件循环,并有望接收一些数据包并设置标志。一个合适的解决方案是将处理程序附加到
readyRead
信号,然后返回到事件循环中。

您正在释放三条UDP消息,并期望在相同的毫秒内返回响应。这在网络方面是行不通的。此外,默认情况下,Qt UDP套接字是非阻塞的。作为一种快速攻击,您可以调用
m_socket->waitForReadyRead()
,但正确的解决方案是将处理程序附加到
readyRead
信号并返回到事件循环中。多亏了这一点,套接字在发送负载后立即关闭。我用waitForReadyRead()解决了这个愚蠢的错误,原因是我被迫执行发现阻塞。
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 3
sendto(3, "M-SEARCH * HTTP/1.1\nHOST: 239.25"..., 171, 0, {sa_family=AF_INET, sin_port=htons(1900), sin_addr=inet_addr("239.255.255.250")}, 16) = 171
sendto(3, "M-SEARCH * HTTP/1.1\nHOST: 239.25"..., 171, 0, {sa_family=AF_INET, sin_port=htons(1900), sin_addr=inet_addr("239.255.255.250")}, 16) = 171
sendto(3, "M-SEARCH * HTTP/1.1\nHOST: 239.25"..., 171, 0, {sa_family=AF_INET, sin_port=htons(1900), sin_addr=inet_addr("239.255.255.250")}, 16) = 171
ioctl(3, FIONBIO, [1])                  = 0
clock_gettime(CLOCK_MONOTONIC, {tv_sec=10531, tv_nsec=209135513}) = 0
poll([{fd=3, events=POLLIN}], 1, 3000)  = 1 ([{fd=3, revents=POLLIN}])