C++ QUdpSocket在高频环境中的极限
我的任务是以~10kHz的读取速率处理UDP数据。我正在使用Qt5.13.1(MinGW32),所以我尝试使用C++ QUdpSocket在高频环境中的极限,c++,qt,event-handling,udp,qudpsocket,C++,Qt,Event Handling,Udp,Qudpsocket,我的任务是以~10kHz的读取速率处理UDP数据。我正在使用Qt5.13.1(MinGW32),所以我尝试使用QUdpSocket 我做了一个简单的测试程序,但结果有点令人沮丧。readyRead()信号太慢了。由于某些原因,每2-4个信号就会有超过1或2毫秒的延迟。 我制作了一个简单的包计数器,并将其与wireshark中的内容进行比较。果然有数据包丢失 我可以做些什么来提高绩效?或者这只是Qt事件循环的极限 我用QtCreator4.10.0运行它。在Windows7上 更新:根据您的建议:
QUdpSocket
我做了一个简单的测试程序,但结果有点令人沮丧。
readyRead()
信号太慢了。由于某些原因,每2-4个信号就会有超过1或2毫秒的延迟。我制作了一个简单的包计数器,并将其与wireshark中的内容进行比较。果然有数据包丢失 我可以做些什么来提高绩效?或者这只是Qt事件循环的极限 我用QtCreator4.10.0运行它。在Windows7上 更新:根据您的建议:我尝试了:
#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=新的netWorker(&dataServerSocket);
netWorker->moveToThread(&netThread);
netWorker->getInnerLoop()->moveToThread(&netThread);
连接(&netThread,SIGNAL(started()),netWorker,插槽(serversocketprocessing());
连接(&this->dataServerSocket,SIGNAL(readyRead()),netWorker->getInnerLoop(),SLOT(quit());
QString address=“127.0.0.3:16402”;
QHostAddress ip(地址拆分(“:”)位于(0));
quint16端口=地址.split(“:”).at(1).toUShort();
绑定(ip,端口);
//setSocketOption(QAbstractSocket::LowDelayOption,1);
dataServerSocket.moveToThread(&netThread);
netThread.start();
//dataServerSocket.setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption,128000);
//qDebug()pendingDatagramSize());
}
如果(乘以.size()>=10000){
长和=0;
用于(整数x:次){
//qDebug()在测量代码的时间关键部分时,我建议避免使用qDebug(或任何其他慢速打印/调试功能)。它可能会对实际测量产生太大的影响
我的建议是,将从QElapsedTimer接收到的计时值存储到单独的容器(例如QVector,或者仅存储一个随时间平均的qint64),并且每隔一段时间只显示一次调试消息(每秒或仅在最后显示一次)。这样,测量造成的开销影响较小。较长时间内的平均值也将有助于测量结果的差异
我还建议您使用QeReleasedTimer::nsecsAppeased,以避免在高频情况下出现舍入问题,因为QeReleasedTimer::Appeased将始终舍入到最接近的毫秒(并且您已经在1ms区域内测量)
在实际显示结果时,始终可以将纳秒转换为毫秒
以10kHz频率接收的数据大小是多少?在测量代码的时间关键部分时,我建议避免使用qDebug(或任何其他慢速打印/调试功能)。它可能会对实际测量产生太大的影响
我的建议是,将从QElapsedTimer接收到的计时值存储到单独的容器(例如QVector,或者仅存储一个随时间平均的qint64),并且每隔一段时间只显示一次调试消息(每秒或仅在最后显示一次)。这样,测量造成的开销影响较小。较长时间内的平均值也将有助于测量结果的差异
我还建议您使用QeReleasedTimer::nsecsAppeased,以避免在高频情况下出现舍入问题,因为QeReleasedTimer::Appeased将始终舍入到最接近的毫秒(并且您已经在1ms区域内测量)
在实际显示结果时,始终可以将纳秒转换为毫秒
您以10kHz的速率接收的数据大小是多少?您无法在Windows上以如此高的速率接收套接字数据包。这是操作系统的限制。即使使用并将接收代码移动到无限循环中,如下所示:
socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
...
for (;;)
{
if(socket->waitForReadyRead(1)) // waits for some events anyway
{
// read here
}
}
或者,您可以在数据包结构中嵌入一些时间代码字段,并将几个数据包一起发送,或者使用一些不会丢失数据包的连接。例如,使用,因为套接字的下一种情况是可能的:
- 收到完整数据包
- 只收到了数据包的一部分
- 一起收到了几个包
另外,不要尝试
如果缓冲区大小被限制为某个大小,QAbstractSocket将不会
缓冲区大于此数据大小。例外情况下,缓冲区大小为
0表示读取缓冲区不受限制,并且所有传入数据都不受限制
缓冲。这是默认值
如果您仅在中的某些点读取数据,则此选项非常有用
时间(例如,在实时流媒体应用程序中)或
保护您的套接字,防止接收太多数据,这可能会
最终导致应用程序内存不足
只有QTcpSocket使用QAbstractSocket的内部缓冲区;QUdpSocket
根本不使用任何缓冲,而是依赖于隐式
操作系统提供的缓冲。因此,调用
QUdpSocket上的此函数无效
您无法在Windows上以如此高的速率接收套接字数据包。这是操作系统的限制。即使使用并且如果将您的接收代码移动到无限循环中,如下所示:
socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
...
for (;;)
{
if(socket->waitForReadyRead(1)) // waits for some events anyway
{
// read here
}
}
或者,您可以在数据包结构中嵌入一些时间代码字段,并将几个数据包一起发送,或者使用一些不会丢失数据包的连接。例如,使用,因为套接字的下一种情况是可能的:
#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;
}
}
}
socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
...
for (;;)
{
if(socket->waitForReadyRead(1)) // waits for some events anyway
{
// read here
}
}