QT 通过QNetworkAccessManager进行http请求的超时与同步异步处理
- QNetworkAccessManager是QT的网络包,可以设置超时,见下面代码。
QReplyTimeout *pTimeout = new QReplyTimeout(reply, 2000);
// 超时进一步处理
connect(pTimeout, &QReplyTimeout::timeout, [=]() {
qDebug() << "Timeout";
this->loginMutex.unlock();
return;
});
- 但是默认是异步的,每次点击执行发起http请求时会新开一个线程执行,主函数立即就结束了,读数据以槽函数的形式在另一个线程读取。这样有一定优势,不占用主线程资源,但是有个问题是如果确实需要同步的情形,或者访问在返回前只需要一次,这样防止重复提交。网上实现方法主要是通过阻塞的形式,如下:
QEventLoop eventLoop;
connect(pManger2, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
eventLoop.exec(); //block until finish
这种方式在一定程度上可以实现同步,但是在测试过程中重复频繁发起请求时,由于多线程同时对reply进行操作,会出现段错误,很难通过较验来判断。
而且,这种方法阻塞了主线程,会对程序有影响。
- 于是想到了另一种方法,那就是加锁,通过Qmutx的tryLock,和unlock的来进行控制,完美的实现了访问控制,同时只访问一次(而且是非阻塞)。当然unlock要放在两个地方,一个是超时的槽函数里,另一个是接收槽函数内。需要进一步测试会不会有其他异常。
void MainWindow::on_readyRead(){
qDebug() << reply->error() << endl;
QByteArray resp = reply->readAll();
ui->textEdit->append(resp);
qDebug()<<"on_readyRead"<<endl;
this->loginMutex.unlock();
}
void MainWindow::on_pushButton_clicked()
{
if (!this->loginMutex.tryLock()) {
qDebug() << "already locked return" << endl;
return;
}
pManger = new QNetworkAccessManager(this);
//pManger = new QNetworkAccessManager();
reply= pManger->get(QNetworkRequest(QUrl("http://www.csdn.net")));
QReplyTimeout *pTimeout = new QReplyTimeout(reply, 2000);
// qDebug()<<reply->readAll()<<endl;
// 超时进一步处理
connect(pTimeout, &QReplyTimeout::timeout, [=]() {
qDebug() << "Timeout";
this->loginMutex.unlock();
return;
});
connect(reply,SIGNAL(finished()),this,SLOT(on_readyRead()));
qDebug()<<""<<endl;
qDebug()<<"after ret 异步"<<endl;
}