PDA

View Full Version : Problem writing too fast to QUdpSocket



mwvse
11th April 2020, 21:48
Hi,

Using Qt 5.14.1.

If I write back to back on a QUdpSocket, the subsequent datagrams never make it out. For example:


#include <QCoreApplication>
#include <QUdpSocket>
#include <QTextStream>
#include <QThread>

int main(int argc, char *argv[])
{
QTextStream cout(stdout);
QUdpSocket myUdpSocket;

myUdpSocket.connectToHost("127.0.0.1", 50000);

cout << myUdpSocket.write("msg 1\n") << Qt::endl;
cout << myUdpSocket.write("msg two\n") << Qt::endl;

QThread::currentThread()->sleep(5);

return 0;
}

Both writes return that they wrote the expected number of bytes (6 and 8).

Per Wireshark, only the first write (i.e., "msg 1\n") is actually sent out.

"1","0.000000","127.0.0.1","127.0.0.1","UDP","58","54399 ? 50000 Len=6","msg 1\n"

If I put in a delay, then it works:


cout << myUdpSocket.write("msg 1\n") << Qt::endl;

QThread::currentThread()->sleep(1);

cout << myUdpSocket.write("msg two\n") << Qt::endl;

Wireshark output:

"1","0.000000","127.0.0.1","127.0.0.1","UDP","58","53420 ? 50000 Len=6","msg 1\n"
"2","1.000014","127.0.0.1","127.0.0.1","UDP","68","53420 ? 50000 Len=8","msg two\n"

I also tried waitForBytesWritten(), and that didn't work (the calls to it each return false):


cout << myUdpSocket.write("msg 1\n") << Qt::endl;

cout << myUdpSocket.waitForBytesWritten(1000) << Qt::endl;

cout << myUdpSocket.write("msg two\n") << Qt::endl;

cout << myUdpSocket.waitForBytesWritten(1000) << Qt::endl;

I am fairly new to Qt so my apologies if I am missing something seemingly obvious. Any help understanding why QUdpSocket and/or write() is behaving this way is greatly appreciated. Thank you.

ChrisW67
13th April 2020, 02:08
You are using the QIODevice interface. You are writing into a buffer (successfully) and leaving Qt to determine when the bytes actually go on the wire. In general this requires an application object and a Qt event loop to be running and you are providing neither.

Try something like this:
#include <QCoreApplication>
#include <QUdpSocket>
#include <QTimer>
#include <QObject>
#include <QDebug>

class Sender: public QObject {
Q_OBJECT
public:
Sender(QObject *p = nullptr):
myUdpSocket(new QUdpSocket(this)) {
myUdpSocket->connectToHost("127.0.0.1", 50000);

connect(myUdpSocket, &QUdpSocket::bytesWritten, this, &Sender::sentStuff);

QTimer::singleShot(0, this, &Sender::sendStuff);
// ^^^ delays sending stuff until event loop is running
// and this timer event is processed
}
~Sender() { }
private slots:
void sendStuff() {
qDebug() << myUdpSocket->write("msg 1\n");
qDebug() << myUdpSocket->write("msg two\n");
}
void sentStuff(qint64 bytes) {
qDebug() << "Bytes sent:" << bytes;
}
private:
QUdpSocket *myUdpSocket;
};


int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv); // << application object
Sender s;
return app.exec(); // << event loop
}

#include "main.moc"

mwvse
15th April 2020, 20:41
Thank you ChrisW67 very much for the reply. Using your code example with no modifications. I still get the same result.

Here is my console output:

13395

And here is my wireshark output:

13397

Any other thoughts about this are greatly appreciated. Thanks.

mwvse
16th April 2020, 00:13
Thanks to the help from others on various forums, I believe the problem has to do with the following (at least under Windows):

https://stackoverflow.com/questions/29764906/missing-udp-sent-packets

Here is an excerpt:



Microsoft has addressed this type of UDP drops during ARP resolution in the past. It is possible/likely the behavior remains in current implementations.

From ARP and UDP Messages

ARP queues only one outbound IP datagram for a given destination address while that IP address is being resolved to a MAC address. If a UDP-based application sends multiple IP datagrams to a single destination address without any pauses between them, some of the datagrams might be dropped if there is no ARP cache entry present. An application can compensate for this by calling the Iphlpapi.dll routine SendArp() to establish an arp cache entry, before sending the stream of packets. See the platform Software Development Kit (SDK) for additional information.



The following code delays after the first write, then runs 1000 at full speed and none of the writes get dropped. If you remove that first delay, only the first write gets sent out (even when using 127.0.0.1):



#include <QCoreApplication>
#include <QUdpSocket>
#include <QTextStream>
#include <QThread>

int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);

QTextStream cout(stdout);
QUdpSocket* myUdpSocket = new QUdpSocket;

myUdpSocket->connectToHost("127.0.0.1", 50000);

cout << myUdpSocket->write("msg 1\n") << Qt::endl;
QThread::currentThread()->sleep(1);

for(unsigned u = 0; u < 1000; u++)
cout << myUdpSocket->write("another\n") << Qt::endl;

QThread::currentThread()->sleep(5);

return 0;
}