C++ Qt/C++;SSDP发现
我正在尝试为sonos扬声器编写一个小型控制器二进制文件。为此,我希望执行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
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}])