c++ - QUdpSocket在高频环境下的局限

标签 c++ qt event-handling udp qudpsocket

我的任务是处理读取速率约为 10kHz 的 UDP 数据。我正在使用 Qt 5.13.1 (MinGW32),所以我尝试使用 QUdpSocket
我做了一个简单的测试程序,但结果有点令人沮丧。 readyRead() 信号太慢了。出于某种原因,我每 2-4 个信号就有超过 1 或 2 毫秒的延迟。
我制作了一个简单的数据包计数器并将其与我在 wireshark 中看到的进行比较。果然有丢包。

我可以做些什么来提高性能?或者这可能只是 Qt 事件循环的限制?

我用 Qt Creator 4.10.0 运行它。在 Windows 7 上。

更新:根据您的建议:我试过了:

  1. 在不同线程中移动套接字。这提供了更多的性能 .. 有一点

  2. LowDelayOption = 1 - 我没有注意到任何变化

  3. ReceiveBufferSizeSocketOption - 我没有注意到任何变化

  4. 阅读时没有使用 QDebug - 我没有检查它,只是用于 收集统计数据

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();

网络 worker .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

网络 worker .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;
        }

    }
}

最佳答案

你不能在 Windows 上以如此高的速率接收套接字数据包。这是操作系统的限制。即使使用 QAbstractSocket::LowDelayOption如果将您的接收代码移动到这样的无限循环中:

socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
...

for (;;)
{
    if(socket->waitForReadyRead(1)) // waits for some events anyway
    {
        // read here
    }
}

或者,您可以将一些时间码字段嵌入到您的数据包结构中,并将多个数据包一起发送,或者使用一些不会丢失数据包的连接。例如,使用 TCP connection + transactions因为套接字可能会出现以下情况:

  • 收到完整数据包
  • 只收到部分数据包
  • 一起收到了几个数据包

此外,不要尝试 to change readBufferSize:

If the buffer size is limited to a certain size, QAbstractSocket won't buffer more than this size of data. Exceptionally, a buffer size of 0 means that the read buffer is unlimited and all incoming data is buffered. This is the default.

This option is useful if you only read the data at certain points in time (e.g., in a real-time streaming application) or if you want to protect your socket against receiving too much data, which may eventually cause your application to run out of memory.

Only QTcpSocket uses QAbstractSocket's internal buffer; QUdpSocket does not use any buffering at all, but rather relies on the implicit buffering provided by the operating system. Because of this, calling this function on QUdpSocket has no effect.

关于c++ - QUdpSocket在高频环境下的局限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58592759/

相关文章:

c++ - "Default member initializer needed within definition of enclosing class outside of member functions"- 我的代码格式不正确吗?

c++ - 没有 DllRegisterServer 等的 COM dll

c++ - QGraphicsView Qt 的点击事件

qt - 如何在 Qt5.5 qml TreeView 中右键单击时显示上下文菜单

c++ - 将 Axis2C 与 Qt 数据结构耦合

c++ - 删除存储在数组中的特定类对象

c++ - 获取 QT 代码的纯 C++ 实现

c++ - 取消引用指向 size_t 的指针,但从 void 指针转换

javascript - JavaScript 中的事件处理

javascript - 表格单元格未将其 ID 传递到我的函数参数中