PDA

View Full Version : QUdpSocket readyRead failure



mike66
19th November 2015, 04:31
Hi everyone

This is my first post here and I can see its a question that has been raised a number of times. It concerns the reliability of the QUdpSocket. I've read other posts on the subject, but got various suggestions but no definitive answers, so I'll explain my problem here ...

I have an application created in Qt5.5 running on Ubuntu14.04. Its receiving small udp datagrams from a remote device. The datagrams are all less than 15 bytes of data. The datagrams normally arrive about once per second, but every few seconds two datagrams will arrive in quick succession. I can monitor on Wireshark, and these two quick datagrams are logged about 5msecs apart.

My application code is based exactly on the QUdpSocket example in Qt documentation, (see below) and its all running in the main GUI thread.


void Server::initSocket()
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::LocalHost, 7755);

connect(udpSocket, SIGNAL(readyRead()),
this, SLOT(readPendingDatagrams()));
}

void Server::readPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;

udpSocket->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);

processTheDatagram(datagram);

//additional debug code
qDebug() << "Bytes available = " << udpSocket->bytesAvailable();
}
}


My application can run for days with no problem then it just stops receiving datagrams. I am aware of the nature of the readyRead() signal being not being processed if it occurs during the readPendingDatagrams() slot, and the code seems to take care of this successfully using the


while (udpSocket->hasPendingDatagrams())
{

}


code to ensure any datagrams received while the slot is being processed are read in before exiting the slot.
I added in a qDebug() line at the end of the readPendingDatagrams() slot to check the operation of the slot.

As expected normally the qDebug message normally prints 'Bytes avalable = 0', except when the two datagrams arrive in quick succession the qDebug message then sometimes prints 'Bytes available = 4' correctly indicating the presence of my second 4 byte datagram which has subsequently arrived and is waiting to be processed. The readPendingDatagrams() slot then loops again to process that data. All good as expected

However, as already stated, my application just stops receiving randomly, somtimes a few times a day other times running for days with no problem. Every time the application fails its when the two datagrams are received in quick succession. I have now created a simple button on my user interface that can query the socket manually reading


udpSocket->bytesAvailable();


on demand.

Here is what I found...

When my application fails its always at the two quick succession datagrams.
The first datagram is always received successfully.
My


qDebug() << "Bytes available = " << udpSocket->bytesAvailable();


prints 'Bytes available = 0', indicating the second datagram has not yet arrived, and the readPendingDatagrams() slot exits.
No other datagrams are received after this.
When the application stops receiving I can click the new button I have created and it reports that there are infact 4 bytes Available !!!!

It seems as though there is a moment, between where the readPendingDatagrams() slot checks for


udpSocket->hasPendingDatagrams()


and where it finally returns, that the readyRead() signal from the next datagram can be asserted and missed.

Has any one else observed this, and is there a common remedy.

mike66
22nd November 2015, 11:56
177 reads, and ZERO replies !

Did I, somehow, accidentally set the thread permissions as 'Read Only' ?

ChrisW67
22nd November 2015, 20:18
Is the last datagram you receive intact and the size you expected?
Does the program fail in the same way if you never call processTheDatagram()? Is the processing exhausting system resources over time causing the networking to fail as a side effect?

mike66
23rd November 2015, 01:23
Hi ChrisW67

Thanks for your reply.

The last datagram received is always complete and the right size.
I've never tried testing the program without processing the datagram. The program is essentially just about receiving these datagrams so does almost nothing without them.
The process does not appear to exhaust system resources. The memory usage of the program is pretty consistant over days of running. I ran a 'Valgrind' test on it and it appears to have no memory leaks.

The network does not actually fail. I can start up wire shark and see the datagrams arriving, they are just not firing the readyRead() signal.
In my program, I can now check the status of the network socket on demand by clicking a button. When the program stops receiving datagrams, I check the socket status using


udpSocket->hasPendingDatagrams()


it returns true.

I also check


udpSocket->bytesAvailable();


and that returns a value of 4, which is exactly the size of the next datagram. Its been received and is sitting there waiting to be read. It just didn't appear to send the readyRead() signal from the socket.

I'm getting to the point where I think I need a timer to keep checking for this condition, but its not a nice solution at all.

Anybody else using sockets and protect against this situation? Any suggestions wold be greatly appreciated.

Added after 5 minutes:

I created an account at the Qt Bug Tracker site this morning.

https://bugreports.qt.io/secure/Dashboard.jspa

I looked at the bug reports and there it is. Bug 46552 exactly what I am experiencing.
A month or so ago I upgraded from Qt 5.2.1 to Qt5.5.0, and it appears this bug is in Qt5.4.2 and 5.5.0
For anyone out there with these versions - BEWARE !

jefftee
25th November 2015, 21:42
177 reads, and ZERO replies !
I have read your post multiple times and started multiple replies, only to cancel out once I realize I don't know what I'm talking about for certain, but here goes... :)

You would have to inspect the QUdpSocket, QIODevice, and perhaps QAbstractSocket code to confirm this, but I can see where bytesAvailable, which is a QIODevice inherited method would have bytesAvailable but are somehow not yet readable by the socket. That may not make logical sense to you or I, but it all depends on how these methods are implemented of course.

I see that @ChrisW asked and you confirmed that last datagram is always complete, with a payload of 4 bytes each time. I would suggest a couple of things to try:

1) Eliminate the processTheDatagram function call in your loop, where you simply check for hasPendingDatagrams and then readDatagram to see if you continue to receive the readyRead signals. If so, then check processTheDatagram to see how/if you may be blocking the event loop, etc.

2) If you have control of the sending program, pad that last payload to be a larger size, say 32 bytes as a guess just to see if you may have found some bug that exists with extremely small payloads. I would consider a complete payload of 4 bytes very small, especially when payloads typically contain some type of self describing information (packet type, length, etc) so that the receiving program can ensure complete packets are receive and not split, etc.

Those are the two things I would do first to try to figure out what's going on. Hope that helps in some way!

mike66
26th November 2015, 23:00
Hi Jefftee

Thanks for taking the time to think about this problem and for your suggestions.
However, at the bottom of my last post there are a few paragraphs ...




I created an account at the Qt Bug Tracker site this morning.

https://bugreports.qt.io/secure/Dashboard.jspa

I looked at the bug reports and there it is. Bug 46552 exactly what I am experiencing.
A month or so ago I upgraded from Qt 5.2.1 to Qt5.5.0, and it appears this bug is in Qt5.4.2 and 5.5.0
For anyone out there with these versions - BEWARE !


I'm actually upgrading to qt5.5.1 as it seems the bug has been fixed in the new version. Time will tell !

But, thanks again for your input.