Singleton QNetworkAccessManager 没有将响应定向到所需的形式

Singleton QNetworkAccessManager not directing the response to desired form

在一个小型 Qt 应用程序中,我有一个封装在单例中的 NetworkAccessManager(NAM) class。此 class 的 NAM 对象由四个独立的形式 classes 使用。每个表单 class 都会向单独的 php 发出请求(并且 php 至少需要 3 秒的睡眠(3))。

现在有两种情况:

情况一:当 NAM 为每个表单连接到表单在构造函数中的插槽时。 在这种情况下,当我同时发送所有四种形式的请求时;所有响应都指向一个表单(第一个触发请求的表单),而不是请求它的表单。

情况 II:当 NAM 连接(用于触发请求)和断开连接(当收到响应时)到窗体的 slot IN FUNCTIONS(而不是构造函数)。 在这种情况下,当我同时从所有四种形式发送请求时(即不到 3 秒);然后只返回第一个响应,其余的永远不会返回。这与代码一致,因为单例 NAM 在收到第一个请求的回复后立即断开连接。因此无法处理其他请求。

所有形式 class 都是相同的并且使用相同的代码。这是代码(特定于案例 II):

void Request2::slotStartRequest(){
   m_Req2 = NetworkAccessManager::getInstance();
   connect(m_Req2, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotReplyFinished(QNetworkReply*)));
   QString postData = "value=222";
   m_Req2->post(QNetworkRequest(QUrl(path)), postData.toUtf8());
}

void Request2::slotReplyFinished(QNetworkReply *reply){
   disconnect(m_Req2, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotReplyFinished(QNetworkReply*)));
   ui->TEdit_Req2->setText(reply->readAll());
   reply->deleteLater();
}

尽管这两种情况的代码非常相似。此代码特定于案例 II。对于案例 I,唯一的变化是 'connect' 和 'getInstance' 代码放在构造函数中(没有 'disconnect')。

每个表单使用一个 NetworkAccessManager 对象时,代码可以正常工作 class。

但是我如何实现预期的行为(整个应用程序使用一个 NAM),即响应仅针对请求它的表单,并且对其他表单的请求不应该受到影响?

我的建议(我所做的)是跟踪哪个对象向管理器发出请求,也许更新您的管理器以接收对象指针

m_Req2->post(QNetworkRequest(QUrl(path)), postData.toUtf8(), this);

然后在 Manager 上,使用该指针并使用 QMetaObject 调用方法,而不是发出信号:http://doc.qt.io/qt-5/qmetaobject.html#invokeMethod.

所以你在管理器上得到了这样的东西

QMetaObject::invokeMethod(obj, "slotReplyFinished", Qt::DirectConnection,
                      Q_ARG(QNetworkReply*, reply));

(未测试,但您应该明白)

[编辑:固定代码]

NAM 函数 post() 创建一个新的 QNetworkReply 实例来管理该请求。可以直接连接到 QNetworkReply 信号而不是 QNetworkAccessManager:

的信号
void Request2::slotStartRequest(){
   QString postData = "value=222";
   QNetworkAccessManager *nam = NetworkAccessManager::getInstance();
   m_Reply = nam->post(QNetworkRequest(QUrl(path)), postData.toUtf8());    
   connect(m_Reply, SIGNAL(finished()), this, SLOT(slotReplyFinished()));
}

现在只有QNetworkReply *m_Reply的这个实例可以调用this的信号。请注意,finished() 信号中没有 QNetworkReply *reply 参数:

void Request2::slotReplyFinished(){
   ui->TEdit_Req2->setText(m_Reply->readAll());
   m_Reply->deleteLater();
}