QNetworkAccessManager 不发出完成信号

Posted

技术标签:

【中文标题】QNetworkAccessManager 不发出完成信号【英文标题】:QNetworkAccessManager doesnt emit finished signal 【发布时间】: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);"函数的结尾有没有办法等到所有这些都完成? 【参考方案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 异步。 是的,如果其中一个发生错误,循环将等待等待,最好添加一个计时器来检测异常延迟?

以上是关于QNetworkAccessManager 不发出完成信号的主要内容,如果未能解决你的问题,请参考以下文章

Qt QNetworkAccessManager 发出完成信号的长时间延迟

在发布模式下编译时不会发出 QNetworkAccessManager 完成信号(VS 2005)

QNetworkAccessManager 不会启动

QFtp或QNetworkaccessmanager因系统代理请求报错解决方案

QFtp或QNetworkaccessmanager因系统代理请求报错解决方案

QFtp或QNetworkaccessmanager因系统代理请求报错解决方案