I have a task of processing UDP data with ~10kHz read rate. I'm working with Qt 5.13.1 (MinGW32), so I tried to use a QUdpSocket
.
I made a simple test program, but the results are a bit frustrating. The readyRead()
signal is just too slow. For some reason I'm getting delays over 1 or 2 ms every 2-4 signals.
I made a simple packet counter and compare it with what I see in wireshark. Sure enough there is a packet loss.
What can I do to enhance perfomance? Or maybe it's just the limit of the Qt event loop?
I run it with Qt Creator 4.10.0. On Windows 7.
Update: With your advices: I tried:
Moving socket in different thread. This gives a bit more perfomance .. a very bit
LowDelayOption = 1 - I did not notice any changes
ReceiveBufferSizeSocketOption - I did not notice any changes
- No usage of QDebug while reading - I did not check it, just use for collecting statistics
udpproc.h
#ifndef UDPPROC_H
#define UDPPROC_H
#include "QObject"
#include "QUdpSocket"
#include "QHostAddress"
#include "QThread"
#include "QDebug"
#include "networker.h"
class UDPProc : public QObject
{
Q_OBJECT
public:
UDPProc();
~UDPProc();
private:
QUdpSocket dataServerSocket;
NetWorker* netWorker;
QThread netThread;
};
#endif // UDPPROC_H
udpproc.cpp
UDPProc::UDPProc() {
netWorker = new NetWorker(&dataServerSocket);
netWorker->moveToThread(&netThread);
netWorker->getInnerLoop()->moveToThread(&netThread);
connect(&netThread, SIGNAL(started()), netWorker, SLOT(serverSocketProccessing()));
connect(&this->dataServerSocket, SIGNAL(readyRead()), netWorker->getInnerLoop(), SLOT(quit()));
QString address = "127.0.0.3:16402";
QHostAddress ip(address.split(":").at(0));
quint16 port = address.split(":").at(1).toUShort();
dataServerSocket.bind(ip, port);
//dataServerSocket.setSocketOption(QAbstractSocket::LowDelayOption, 1);
dataServerSocket.moveToThread(&netThread);
netThread.start();
//dataServerSocket.setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 128000);
//qDebug()<<dataServerSocket.socketOption(QAbstractSocket::ReceiveBufferSizeSocketOption).toInt();
}
networker.h
#ifndef NETWORKER_H
#define NETWORKER_H
#include <QObject>
#include "QElapsedTimer"
#include "QEventLoop"
#include "QUdpSocket"
#include "QVector"
class NetWorker : public QObject
{
Q_OBJECT
private:
QElapsedTimer timer;
QVector<long long> times;
QEventLoop loop;
QUdpSocket *dataServerSocket;
char buffer[16286];
int cnt = 0;
public:
NetWorker(QUdpSocket *dataServerSocket);
~NetWorker();
QEventLoop * getInnerLoop();
public slots:
void serverSocketProccessing();
};
#endif // NETWORKER_H
networker.cpp
#include "networker.h"
NetWorker::NetWorker(QUdpSocket *dataServerSocket)
{
this->dataServerSocket = dataServerSocket;
}
NetWorker::~NetWorker()
{
delete dataServerSocket;
}
QEventLoop *NetWorker::getInnerLoop()
{
return &loop;
}
void NetWorker::serverSocketProccessing()
{
while(true){
timer.start();
loop.exec();
times<<timer.nsecsElapsed();
while(dataServerSocket->hasPendingDatagrams()){
dataServerSocket->readDatagram(buffer, dataServerSocket->pendingDatagramSize());
}
if (times.size() >= 10000){
long long sum = 0;
for (int x : times){
//qDebug()<<x;
sum += x;
}
qDebug() << "mean: "<<sum/times.size();
break;
}
}
}
You cannot receive socket packets on Windows with so high rate ever. It is limit of the operating system. Even using QAbstractSocket::LowDelayOption and if move your receiving code into an infinite loop such this:
Alternatively, you can embed some time code field into you data packet structure and send several packets together instead or use some connection where are no packet lost. As example, use TCP connection + transactions because the next situations are possible for a socket:
Also, do not try to change readBufferSize: