【发布时间】:2016-12-01 17:50:38
【问题描述】:
我刚刚遇到了来自 QUdpSocket 的 readyRead() 信号的困难时期,虽然我找到了一个解决方案,但我仍然不确定我做了什么,但我想更准确地了解我的解决方案为什么真正有效。这是我的情况:
我已连接到发出通知的服务器。 当我收到它们时,即当我的 QUdpSocket 发出 onReadyRead() 时,我会处理通知:解包数据,检查它的来源等。这是在继承 QObject 的自定义对象中完成的。
然后这个对象发出一个信号“notificationReceived”,以便其他对象可以处理该通知:notificationReceived() 信号连接到一个 processNotification() 槽。
processNotification() 依次执行一些操作,包括向服务器执行新的 GET 请求。 服务器接收请求并做出响应。但是,来自 QUdpSocket 的 readyRead() 信号没有在我的应用程序中发出,它的行为就像它从未从服务器接收到数据报一样。
但是当我调用 'my_socket->hasPendingDatagrams()' 时,它返回 true,我可以读取实际存在的数据报,并且与我在 GET 请求中想要的内容相对应:
MyCustomObject::MyCustomObject(QObject* parent){
// constructor
my_socket = new QUdpSocket(this);
if (!m_socket->bind(QHostAddress::Any, m_port, QAbstractSocket::ShareAddress))
qDebug() << "Could not bind to port" << m_port << m_socket->errorString();
connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
}
void MyCustomObject::onReadyRead(){
QHostAddress hostAddress;
QByteArray data;
quint16 port;
while (m_socket->hasPendingDatagrams()) {
data.resize(my_socket->pendingDatagramSize());
my_socket->readDatagram(data.data(), data.size(), &hostAddress, &port);
}
processResponse(data, hostAddress, port);
}
void MyCustomObject::processNotification(QByteArrayData){
// do some checking and reading of data
// when finished:
getNewData();
}
void MyCustomObject::getNewData(){
// instantiate data, hostAdress, port. In other words :
// create the request in the form of a datagram to be sent
my_socket->writeDatagram(data, hostAdress, port);
}
所以我尝试了解 readyRead() 信号并理解为什么在这种情况下它没有发出。特别是这篇文章给了我一个线索: http://www.qtforum.org/article/1118/2/signal-readyread-doesn-t-work.html
它讲述了线程问题。但是我的应用程序是从 QGuiApplication 运行的,并且一切都在一个线程中完成(据我所知,我实际上对线程了解不多)。
最后,我的解决方案是:直接从 processNotification() 槽接收到 notificationReceived() 信号后,我不执行我的 GET 请求,而是使用 QTimer::singleShot 调用 GET 请求。 所以我做了类似(简化)的事情:
void processNotification(QByteArray data){
// check some conditions
// process the data, and when finished:
QTimer::singleShot(1000, this, SLOT(getData()));
}
并且 getRequest() 负责向服务器发送一个 GET,这一次检测到服务器的响应(my_socket 发出 readyRead() 信号)。虽然我仍然不确定为什么。
注意:如果我不使用,在 notificationReceived() 第一次发出的信号和从最终触发的 slot() 调用 getRequest() 之间发出/接收多少 signal()、slot() 并不重要一个QTimer到底是不行的。
【问题讨论】:
-
您可能错误地认为 HTTP 服务器实际上已经向您发送了一个 UDP 数据报。使用 Wireshark 确认这样的数据报实际上已经到达您的系统。旁注:当您传递 Qt 容器和其他值类型时,请通过 const 引用传递它们。因此你应该有
void processNotification(const QByteArray &data)等。你也可以通过值来保存套接字,没有理由通过指针来保存它。 -
是的,我确定服务器发送了一个数据报,首先是因为我看到它是在服务器端发送的,其次是因为如果我调用 my_socket->hasPendingDatagrams() 我实际上是在客户端收到它.问题只是即使某些数据正在等待读取,也不会发出 onReadyRead()。
-
好的,那么确切的操作系统版本和构建是什么,它的 Qt 版本是什么?