我刚从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()第一个发出的信号和从最终的trigerred slot()调用getRequest()之间发出/接收多少signal(),slot()无关紧要? QTimer最终无效。
答案 0 :(得分:1)
我认为您的问题是您正在同一线程和事件循环中进行所有操作。
即在您的readyRead()插槽中,您正在调用processResponse(...),该操作将立即执行,然后当processResponse发出“ notificationReceived()”信号并调用processNotification()时,最终将调用getNewData()。>
所有这些调用都将“在线”完成(请参阅有关Qt的DirectConnetion的SIGNAL链接),因此您基本上是在请求newData的同时仍在readyRead()函数调用中。
如果服务器在您的代码流返回正常事件循环之前做出响应,则您将丢失新的readyRead()调用。
为什么使用QTimer解决了您的问题?因为基本上是您推迟了getNewData,并且您的调用堆栈会离开readyRead()并进入普通事件循环,在之前,您实际上已请求了一些新数据。