Unsolved QUdpSocket doesn't trigger readyread signal
-
@KroMignon said in QUdpSocket doesn't trigger readyread signal:
2341
Yes it is. The weird thing is, that with an older QT version (4.7.1 or something like this) it worked. And again, if I trigger the readyRead signal, or if I stay in a while loop and read the pending datagrams, I get the information which has been sent already. Its just the readyRead signal which somehow doesn't get emitted....
Is there any other way to debug this? I will try another port, but I used the exact same port with qt4
-
@Raffael-Sakrenz said in QUdpSocket doesn't trigger readyread signal:
Is there any other way to debug this? I will try another port, but I used the exact same port with qt4
Okay, now I think I got it!
No, this is not a port number issue.One thing to note, is that
QUdpSocket
emitsreadyRead()
only for one datagram and that if you don't read it, the class will not emit again.
So you have to read all pending datagrams before nextreadyRead()
can be emitted.Something like:
void MyClass::OnUdpReceiveHmi() { while(m_hmiSocket->hasPendingDatagrams()) { QByteArray buffer; buffer.resize(m_hmiSocket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; m_hmiSocket->readDatagram(buffer.data(), buffer.size(), &sender, &senderPort); .... } }
-
Hi @KroMignon :
Thanks for the reply. This is actually the code of my OnUdpReceiveHmi() method. Nevertheless if I didn't have had that code, the readyRead() signal should at least be emitted once, which isn't the case.
I once had a while loop right after the QObject::connect function like this:
while(!m_hmiSocket->hasPendingDatagrams()) {} if (m_hmiSocket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(m_hmiSocket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; m_hmiSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); LOG_INFO(QString("UDP packet received: ").append(datagram.data()).toStdString().c_str()); }
With that piece of code I was able to read the first incoming datagram but after that nothing happened again. Is there any other way to check if the signal gets emitted or is the QObject::connect function the only way to do it?
-
@Raffael-Sakrenz said in QUdpSocket doesn't trigger readyread signal:
while(!m_hmiSocket->hasPendingDatagrams())
{}Why? You block the event loop...
-
@Raffael-Sakrenz said in QUdpSocket doesn't trigger readyread signal:
while(!m_hmiSocket->hasPendingDatagrams())
{}
if (m_hmiSocket->hasPendingDatagrams())This is a dangerous coding style!
Why do you do this?
Please change this towhile(m_hmiSocket->hasPendingDatagrams())
.Other suggestion would be to change to bind statement to:
tBool boundState_hmi = m_hmiSocket->bind(QHostAddress::Any, m_hmiPortIn, QAbstractSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
-
I just did this once, just to check whether datagrams are even arrived on the port. Just right after, I deleted the code again.
The change of the bind statement didn't change anything. My slot is still not being called.
-
@Raffael-Sakrenz said in QUdpSocket doesn't trigger readyread signal:
My slot is still not being called.
Please show your complete code and make sure to not block the event loop. Also try the examples in the QUdpSocket documentation to see if they work for you.
-
@Raffael-Sakrenz said in QUdpSocket doesn't trigger readyread signal:
The change of the bind statement didn't change anything. My slot is still not being called.
Hmm, another idea I've got.
According to your WireShark capture, the datagram are sent very often.
Perhaps you should connect thereadyRead()
signal before doing thebind()
, to avoid datagram reception before connectionreadyRead()
. -
header
class cRecordingService : public QObject, public object<cADTFService> { Q_OBJECT public: ADTF_CLASS_ID_NAME(cRecordingService, "recordingService.daq.service.cid", "Robert Bosch Recording Service"); ADTF_CLASS_DEPENDENCIES(REQUIRE_INTERFACE(IKernel)); cRecordingService(); tResult ServiceEvent(tInt nEventId, tUInt32 ui32Param1 = 0, tUInt32 ui32Param2 = 0, tVoid* pvData = nullptr, tInt szData = 0) override; tResult ServiceInit() override; tResult ServiceShutdown() override; private: // UDP QUdpSocket* m_hmiSocket; static const quint16 m_hmiPortIn = 2341; static const quint16 m_hmiPortOut = 2340; public slots: void OnUdpReceiveHmi(); }
cpp
tResult cRecordingService::intializeUdpPort() { // Initialization of the UDP socket // First create the socket and bind it to the IP address and port on which the HMI sends its messages m_hmiSocket = new QUdpSocket(this); tBool connectSuccess = QObject::connect(m_hmiSocket, SIGNAL(readyRead()), this, SLOT(OnUdpReceiveHmi())); LOG_INFO("### Recording-Tool-Service-Log: connect signal slot success: " + cString::FromType(connectSuccess)); tBool boundState_hmi = m_hmiSocket->bind(QHostAddress::LocalHost, m_hmiPortIn, QUdpSocket::ReuseAddressHint); LOG_INFO("### Recording-Tool-Service-Log: Boundstate of HMI incoming socket: " + cString::FromType(boundState_hmi) + ", info:" + cString(m_hmiSocket->errorString().toStdString().c_str())); RETURN_NOERROR; } void cRecordingService::OnUdpReceiveHmi() { LOG_INFO("### Recording-Tool-Service-Log: OnUdpReceiveHmi triggered!"); while (m_hmiSocket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(m_hmiSocket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; m_hmiSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); LOG_INFO(QString("UDP packet received: ").append(datagram.data()).toStdString().c_str()); } } The code is compiled as a service which runs inside an application. The event loop is not blocked because I tested the slot with another signal/event. I used the destroyed() signal, therefore I added at the end of "initializeUdpPort" delete m_hmiSocket to see if it works and it called directly the corresponding slot.
-
@Raffael-Sakrenz said in QUdpSocket doesn't trigger readyread signal:
The code is compiled as a service which runs inside an application. The event loop is not blocked because I tested the slot with another signal/event. I used the destroyed() signal, therefore I added at the end of "initializeUdpPort" delete m_hmiSocket to see if it works and it called directly the corresponding slot.
Your "event loop check" looks strange to me.
Why not simply try with QTimer::signelShot()?
Another thing, I would recommend you to use new connect syntax to enable connect check at compilation time:// Initialization of the UDP socket // First create the socket and bind it to the IP address and port on which the HMI sends its messages m_hmiSocket = new QUdpSocket(this); tBool connectSuccess = connect(m_hmiSocket, &QUdpSocket::readyRead, this, &cRecordingService::OnUdpReceiveHmi); LOG_INFO("### Recording-Tool-Service-Log: connect signal slot success: " + cString::FromType(connectSuccess)); tBool boundState_hmi = m_hmiSocket->bind(QHostAddress::LocalHost, m_hmiPortIn, QUdpSocket::ReuseAddressHint); LOG_INFO("### Recording-Tool-Service-Log: Boundstate of HMI incoming socket: " + cString::FromType(boundState_hmi) + ", info:" + cString(m_hmiSocket->errorString().toStdString().c_str())); // Just for test purpose QTimer::singleShot(100, this, [this]() { qDebug() << "### Event loop is working :)." << (m_hmiSocket->hasPendingDatagrams() ? "PENDING DATAGRAM" : "NO DATAGRAM"); });
-
@KroMignon
I tested your suggestion. First there is no datagram but if I switch on my other (sending) application, the datagram is found.I also modified the code and made a cyclic timer, which reads every second the status and if there is a datagram also the datagram itself.
In the end I read the datagram in that timer callback function instead of the slot. I don't understand it. Aren't you able to reproduce the issue?
Is there any way, why the signal could be blocked from being sent? I read in the QT issue tracker, that the QSerialSocket had some issues with readyRead in 5.12....
-
I also tried it with waitForReadyRead() and my slot was called but after the next udp packet its ignored again.