首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QUdpSocket在高频环境中的局限性

QUdpSocket在高频环境中的局限性
EN

Stack Overflow用户
提问于 2019-10-28 14:28:14
回答 2查看 1.1K关注 0票数 1

我有一项处理UDP数据的任务,读取速率约为10 UDP。我正在使用QT5.13.1 (MinGW32),所以我尝试使用QUdpSocket

我做了一个简单的测试程序,但结果有点令人沮丧。readyRead()信号太慢了。出于某种原因,每2-4个信号就会有超过1到2毫秒的延迟。

我制作了一个简单的数据包计数器,并将它与我在wireshark中看到的进行了比较。当然是丢包了。

我能做些什么来提高业绩?或者仅仅是Qt事件循环的极限?

我使用4.10.0运行它。在Windows 7上。

更新:与您的建议:我试过:

  1. 在不同线程中移动套接字。这给了我更多的成就..有一点
  2. LowDelayOption =1-我没有注意到任何更改
  3. ReceiveBufferSizeSocketOption -我没有注意到任何变化
  4. 阅读时不使用QDebug -我没有检查它,只是用于收集统计数据。

udpproc.h

代码语言:javascript
复制
#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() {

代码语言:javascript
复制
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

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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;
        }

    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-29 10:23:04

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

代码语言:javascript
复制
socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
...

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

或者,您可以将一些时间代码字段嵌入到数据包结构中,然后将多个数据包一起发送,或者在没有丢失数据包的地方使用某种连接。例如,使用TCP连接+事务,因为套接字可能出现下一种情况:

  • 接收全包
  • 只接收到包的一部分
  • 一起接收了几个数据包

另外,不要尝试要更改readBufferSize:

如果缓冲区大小受限于某一大小,则QAbstractSocket将不会缓存超过此大小的数据。在特殊情况下,缓冲区大小为0意味着读取缓冲区是无限的,所有传入数据都会被缓冲。这是默认的。 如果只在特定的时间点(例如在实时流应用程序中)读取数据,或者希望保护套接字不受接收太多数据的影响,则此选项非常有用,这可能最终导致应用程序耗尽内存。 只有QTcpSocket使用QAbstractSocket的内部缓冲区;QUdpSocket根本不使用任何缓冲,而是依赖于操作系统提供的隐式缓冲。正因为如此,在QUdpSocket上调用此函数没有任何效果。

票数 2
EN

Stack Overflow用户

发布于 2019-10-28 22:01:43

在测量代码的时间部分时,我建议您避免使用qDebug (或其他任何缓慢的打印/调试功能)。它可能会对你的实际测量产生太大的影响。

我建议您将从QElapsedTimer接收到的定时值存储到一个单独的容器中(例如,QVector,或者只是一个经过时间平均的qint64 ),并且只偶尔显示一次调试消息(每秒钟一次,或者只显示最后一次)。这样,测量造成的开销影响就更小了。在较长的时间内的平均也将有助于您的测量结果的差异。

我还建议您使用QElapsedTimer::nsecsElapsed,以避免在高频情况下出现舍入问题,因为QElapsedTiemr::elapsed将始终旋转到最接近的毫秒(并且您已经在1ms范围内测量东西)。

在实际显示结果时,始终可以将纳秒转换为毫秒。

以10 the速率接收的数据的大小是多少?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58592759

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档