我正在处理我怀疑在使用QNetworkAccessManager
期间发生的程序中的堆栈损坏错误。完整源代码可用here。
从日志输出判断,我猜测在calendar.cpp的第44行异步请求之后触发了该错误。我没有这方面的确凿证据;我只注意到第45行的消息大部分时间都是最后一条日志消息。
以下是第39-46行:
void Calendar::update()
{
// Start calendar download asynchronously. After retrieving the
// file, parseNetworkResponse will take over.
Logger::instance()->add(CLASSNAME, "Fetching update for 0x" + QString::number((unsigned)this, 16) + "...");
_naMgr.get(QNetworkRequest(_url));
Logger::instance()->add(CLASSNAME, "Update request for 0x" + QString::number((unsigned)this, 16) + " was filed.");
}
此HTTP GET请求由Calendar::parseNetworkResponse
插槽处理,该插槽连接到_naMgr
的{{1}}信号。这是第170-174行:
finished
即使第45行上的日志消息不是崩溃后最后出现在日志中的日志消息,日志中始终会有一个更新请求,该消息从未在第174行的日志消息中跟进。这导致我相信HTTP GET请求可能会破坏这里的东西。提交GET请求的网址似乎是正确的。
我认为存在内存损坏的原因之一是即使输入日历列表和我的互联网连接状态保持不变,该错误也不会一直弹出。 (我可以用至少2个日历触发错误。)此外,当我试图了解更多关于失败点的信息时,我看到了this GCC output。我会从void Calendar::parseNetworkResponse(QNetworkReply* reply) {
// TODO: we suspect that sometimes a SIGSEGV occurs within the bounds
// of this function. We'll remove the excessive log calls when we've
// successfully tracked down the problem.
Logger::instance()->add(CLASSNAME, "Got update response for 0x" + QString::number((unsigned)this, 16) + ".");
的内存检查器收集输出以收集其他信息,但我目前没有附近的Linux安装。
这个错误是否与我身边错误使用Qt网络库有关?你有什么其他理论可以解决这个问题吗?这是我第一次处理可能的堆栈损坏,因为我在业余时间做这个独立的爱好项目,我没有人训练我处理这些问题。
答案 0 :(得分:0)
您是一次发送两个请求吗?
我遇到了线程和QNetworkAccessManager的问题,我不得不为它写一个包装器。
好的,我读了你的一些代码,查看QN doco for QNetworkAccessManager,除了完成的信号之外,还有其他一些信号在失败时发出 - 它总是很好的做法来捕捉它们。
在完成处理响应之前,您是否有可能发送另一个获取请求,这可以解释为什么它是间歇性的。
我会一直看着,看看能不能帮忙。
〜丹
答案 1 :(得分:0)
在完成的插槽中,当您处理响应时,将全局标志(bool)设置为“处理”
这样,如果你得到另一个回复,你可以排队,或者你可以忽略它。问题可能更多是由于QNetworkAccessManager分支线程在幕后的某个地方进行处理,这导致您的代码执行访问冲突。
如果你愿意我会跳过你的项目并仔细看看:)
〜丹
我的发送和接收课程:
.h文件
class sendRec : public QObject
{
Q_OBJECT
public:
sendRec(QObject *parent = 0);
sendRec(QUrl);
QString lastError;
QUrl thisURL;
//QNetworkAccessManager manager;
//FUNCTIONS
void doGet();
void doPost(QByteArray*);
void doPut(QString, QString);
void doConnects(QNetworkReply *reply, QNetworkAccessManager *manager);
signals:
void sendResponse(bool, QString*);
public slots:
/** NETWORK_ACCESS_MANAGER_SLOT **/
//SUCCESS SLOTS FOR BOTH
void requestReturned(QNetworkReply * reply );
//FAILURE SLOTS
void proxyAuthFail(const QNetworkProxy & proxy, QAuthenticator * authenticator);
void sslErrorFail(QNetworkReply * reply, const QList<QSslError> & errors);
/** QNETWORK_REPLY_SLOTS **/
//FAILURE SLOTS
void reqError ( QNetworkReply::NetworkError code );
void sslError ( const QList<QSslError> & errors );
};
的.cpp:
#include "sendrec.h"
sendRec::sendRec(QObject *parent) :
QObject(parent)
{
}
sendRec::sendRec(QUrl url) {
thisURL = url;
}
void sendRec::doGet() {
QNetworkRequest request(thisURL);
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkReply *reply = manager->get(request);
doConnects(reply, manager);
}
void sendRec::doPost(QByteArray *message) {
QNetworkRequest request(thisURL);
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkReply *reply = manager->post(request, *message);
doConnects(reply, manager);
}
void sendRec::doConnects(QNetworkReply *reply, QNetworkAccessManager* manager){
//Reply Connects
QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(reqError(QNetworkReply::NetworkError)));
QObject::connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(sslError(QList<QSslError>)));
//manager connects
QObject::connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(requestReturned(QNetworkReply*)));
QObject::connect(manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
this, SLOT(sslErrorFail(QNetworkReply*,QList<QSslError>)));
QObject::connect(manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
this, SLOT(proxyAuthFail(QNetworkProxy,QAuthenticator*)));
}
void sendRec::requestReturned(QNetworkReply * rep ){
qDebug() << "Request Returned";
QVariant status = rep->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if(status != 200 || status == NULL) {
QString *lastError = new QString("ERROR: " + status.toString()
+ " " + rep->readAll());
emit sendResponse(false, lastError);
} else {
QString *retString = new QString(rep->readAll());
*retString = retString->trimmed();
emit sendResponse(true, retString);
}
rep->manager()->deleteResource(rep->request());
rep->manager()->deleteLater();
rep->deleteLater();
sender()->deleteLater();
}