【问题标题】:QNetworkAccessManager doesnt emit finished signalQNetworkAccessManager 不发出完成信号
【发布时间】:2014-01-08 03:13:57
【问题描述】:

我正在尝试使用 QNetworkAccessManager 进行多个请求,即使我连接插槽 QNetworkAccessManager 也无法发出 finished() 信号。

这是我实现的代码。

void GetNetwork::getAction(QStringList *urls, QList<QByteArray> *result)
{
    uint size=urls->size();

    multiGetResult=result;
    getUrls=urls;
    setFlags();

    for(uint x=0;x<size;x++)
    {
        int test=caluculateIndex(x);
       getNAM[test]->get(QNetworkRequest(QUrl(urls->at(x))));
    }


    //qDebug()<<reply->readAll();

    while (!waitWithFlag())  QThread::msleep(15);

    delete threadFlag;
}

bool GetNetwork::setMultipleGet(uint number)
{
    int diff=number-(getNAM.size()-1);

    if(((getNAM.size()-1)+diff)<0)
        return false;

    for(int i=0;i<diff;i++)
    {
        getNAM.append(new QNetworkAccessManager(this));
        connect(getNAM[getNAM.size()-1],SIGNAL(finished(QNetworkReply*)),this,SLOT(handleMultiRequest(QNetworkReply*)));
    }

    for(int i=diff;i<0;i++)
    {
        disconnect(getNAM[getNAM.size()-1],SIGNAL(finished(QNetworkReply*)),this,SLOT(handleMultiRequest(QNetworkReply*)));
        delete getNAM[getNAM.size()-1];
        getNAM.remove(getNAM.size()-1);
    }
    return true;
}

void GetNetwork::handleMultiRequest(QNetworkReply * reply)
{
    int index=getUrls->indexOf(reply->url().toString());

    if(reply->error()!=QNetworkReply::NoError||index==-1)
    {
        QString error=QString("Network Error file:%1 line:%2 error:%3")
                             .arg(__FILE__)
                             .arg(__LINE__)
                             .arg(reply->errorString());

        emit errorOccured(error);
        return;
    }

    multiGetResult->insert(index,reply->readAll());
    threadFlag[index]=true;
}

这些代码有什么问题?我想不通。

谢谢。

【问题讨论】:

  • 你有没有尝试hook错误信号?
  • 您必须返回事件循环才能执行请求并报告结果。带有 while 循环和 sleep 的代码看起来像是阻塞了事件循环(直到结果到达?),因此根本不执行请求。
  • 即,sleep() 会阻塞事件循环,因此会阻塞任何事件处理,包括网络 I/O。同样在 UI 应用程序中,主线程中的 sleep() 是非常糟糕的做法,因为它会使 UI 无响应。
  • 不,它会等到所有线程都完成。但是 qnetworkaccessmanager 没有发出完成的信号,并且函数在这里等待什么。我只是想确保所有获取都在函数结束时完成。
  • 问题是关于 while "(!waitWithFlag()) QThread::msleep(10);"函数的结尾有没有办法等到所有这些都完成?

标签: qt qnetworkaccessmanager


【解决方案1】:

首先,QNetworkAccessManager 不需要单独的线程,因为它在 Qt 4.8.1 之后在内部运行在单独的线程(异步)中。

其次,您仅将 QNetworkAccessManager 的最后一个实例与已完成的插槽连接,而不是这样做,而是将 QNetworkAccessManager 的每个实例与 handleMultiRequest Slot 连接,并在调用插槽时不断增加计数。你不需要睡眠之类的东西,这都是事件驱动的。 所以,

void GetNetwork::handleMultiRequest(QNetworkReply * reply)
{
    int index=getUrls->indexOf(reply->url().toString());

    if(reply->error()!=QNetworkReply::NoError||index==-1)
    {
        QString error=QString("Network Error file:%1 line:%2 error:%3")
                             .arg(__FILE__)
                             .arg(__LINE__)
                             .arg(reply->errorString());

        emit errorOccured(error);
        return;
    }

    count++;
   if(count == num_get_requests)
   {
       emit
         allDone()
   }
}

【讨论】:

  • QNetworkAccessManager可以同时运行6个以上的线程吗?
  • @VeyselBekirMacit 那是针对 HttpPipelining 的,那六个线程是针对同一个请求的。您可以通过编程方式禁用该功能,
【解决方案2】:

我改变了像 Adnan 想法这样的功能

void GetNetwork::handleMultiRequest(QNetworkReply * reply)
{
    int index=getUrls->indexOf(reply->url().toString());

    if(reply->error()!=QNetworkReply::NoError||index==-1)
    {
        QString error=QString("Network Error file:%1 line:%2 error:%3")
                             .arg(__FILE__)
                             .arg(__LINE__)
                             .arg(reply->errorString());

        emit errorOccured(error);
        return;
    }

    multiGetResult->insert(index,reply->readAll());
    threadDoneCounter++;
    if(threadDoneCounter==getUrls->size())
        emit threadsAreDone();
}

和

void GetNetwork::getAction(QStringList *urls, QList<QByteArray> *result)
{
    uint size=urls->size();

    multiGetResult=result;
    getUrls=urls;
    threadDoneCounter=0;

    for(uint x=0;x<size;x++)
    {
        int test=caluculateIndex(x);
       getNAM[test]->get(QNetworkRequest(QUrl(urls->at(x))));
    }



    QEventLoop eLoop;
    connect(this,SIGNAL(threadsAreDone()),&eLoop,SLOT(quit()));
    eLoop.exec();

    disconnect(this,SIGNAL(threadsAreDone()),&eLoop,SLOT(quit()));
}

【讨论】:

  • 本地事件循环是使异步代码看起来同步的完全不合适的方式。它们可能是我所知道的 Qt 中最邪恶和最痛苦的构造(因为一切都可能在 exec() 返回之前发生 - 使应用程序处于不一致的意外状态;只是一个例子:“this”可以被删除)。从长远来看,在不知道自己在做什么的情况下使用它们会导致恐惧和痛苦。最好让 getAction() API 异步。
  • 是的,如果其中一个发生错误,循环将等待等待,最好添加一个计时器来检测异常延迟?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 2018-09-26
  • 1970-01-01
  • 2015-11-30
相关资源
最近更新 更多