阻塞Qt应用程序在下载短文件期间

8

我正在使用Qt4编写一个应用程序。

我需要从给定的http地址下载一个非常短的文本文件。

这个文件很短,但是我的应用程序需要它才能继续运行,所以我希望确保下载是阻塞的(如果文件未找到/不可用,则会超时几秒钟)。

我想使用QHttp :: get(),但这是一个非阻塞方法。

我想可以使用线程:我的应用程序将启动它并等待它完成。 线程将处理下载,并在下载文件后或超时后退出。

但是我无法使其工作:

class JSHttpGetterThread : public QThread
{
  Q_OBJECT

public:
  JSHttpGetterThread(QObject* pParent = NULL);
  ~JSHttpGetterThread();

  virtual void run()
  {
    m_pHttp = new QHttp(this);
    connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));

    m_pHttp->setHost("127.0.0.1");
    m_pHttp->get("Foo.txt", &m_GetBuffer);
    exec();
  }

  const QString& getDownloadedFileContent() const
  {
    return m_DownloadedFileContent;
  }

private:
  QHttp* m_pHttp;

  QBuffer m_GetBuffer;
  QString m_DownloadedFileContent;

private slots:
  void onRequestFinished(int Id, bool Error)
  {
    m_DownloadedFileContent = "";
    m_DownloadedFileContent.append(m_GetBuffer.buffer());
  }
};

在创建线程以启动下载的方法中,我正在做以下操作:
JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait();

但是这样不起作用,我的应用程序一直在等待。看起来似乎从未调用“onRequestFinished”插槽。
有什么想法吗?
是否有更好的方法来实现我正在尝试的功能?
6个回答

5

有点晚了,但是:

不要使用这些等待循环,正确的方法是使用QHttp的done()信号。

从我所看到的requestFinished信号仅用于应用程序完成请求时,数据可能仍在途中。

您不需要新线程,只需设置qhttp:

httpGetFile= new QHttp();
connect(httpGetFile, SIGNAL(done(bool)), this, SLOT(processHttpGetFile(bool)));

在 processHttpGetFile 中,不要忘记清空文件缓存,因为文件可能没有完全写入磁盘。


5

不必使用线程,只需进入循环调用processEvents

while (notFinished) {
   qApp->processEvents(QEventLoop::WaitForMore | QEventLoop::ExcludeUserInput);
}

当标志notFinishedonRequestFinished槽设置时,它将起到作用。

ExcludeUserInput将确保在等待期间忽略与GUI相关的事件。


3

如果你完成了任务,必须调用QThread::quit()exit(),否则你的线程将一直运行...


1

我选择了实现David的解决方案,这似乎是最简单的。

然而,我还需要处理一些其他事情:

  • 我必须为Qt4.3.3(我正在使用的版本)适应QEventLoop枚举值;
  • 我必须跟踪请求ID,以确保在下载请求完成时退出while循环,而不是在另一个请求完成时退出;
  • 我添加了超时功能,以确保在出现任何问题时退出while循环。

以下是结果,作为(更多或更少的)伪代码:

class BlockingDownloader : public QObject
{
  Q_OBJECT
public:
    BlockingDownloaderBlockingDownloader()
    {
      m_pHttp = new QHttp(this);
      connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));
    }

    ~BlockingDownloader()
    {
      delete m_pHttp;
    }

    QString getFileContent()
    {
      m_pHttp->setHost("www.xxx.com");
      m_DownloadId = m_pHttp->get("/myfile.txt", &m_GetBuffer);

      QTimer::singleShot(m_TimeOutTime, this, SLOT(onTimeOut()));
      while (!m_FileIsDownloaded)
      {
        qApp->processEvents(QEventLoop::WaitForMoreEvents | QEventLoop::ExcludeUserInputEvents);
      }
      return m_DownloadedFileContent;
    }

private slots:
    void BlockingDownloader::onRequestFinished(int Id, bool Error)
    {
      if (Id == m_DownloadId)
      {
        m_DownloadedFileContent = "";
        m_DownloadedFileContent.append(m_GetBuffer.buffer());
        m_FileIsDownloaded = true;
      }
    }

  void BlockingDownloader::onTimeOut()
  {
    m_FileIsDownloaded = true;
  }

private:
  QHttp* m_pHttp;
  bool m_FileIsDownloaded;
  QBuffer m_GetBuffer;
  QString m_DownloadedFileContent;
  int m_DownloadId;
};

0

-1

给GUI一些时间等待线程,然后放弃,怎么样?

就像这样:

JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait(10000);  //give the thread 10 seconds to download

或者...

为什么GUI线程必须等待“下载器线程”呢?当应用程序启动时,创建下载器线程,将finished()信号连接到其他对象,启动下载器线程并返回。当线程完成后,它会向其他对象发出信号,该对象可以恢复您的进程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接