背景:需要使用QNetworkAccessManager周期性以及多次发送异步http请求。但是发现程序过了很长时间后就会崩溃,终端报错:
GLib-ERROR **: Creating pipes for GWakeup: Too many open files ...
后来发现原因是每一个周期都会对QNetworkAccessManager进行new操作导致,内存一直没有消失,QNetworkAccessManager进行get时产生的线程应该也没有消失,句柄就会不断的增加。
解决方法:
(1)如果程序中http请求都是同步的话,QNetworkAccessManager使用临时对象即可,函数结束后对象就会销毁,不会出现问题。例如:
QNetworkAccessManager manager;
/*设置http请求*/
QNetworkRequest req;
req.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json;charset=UTF-8"));
...........
/*get http 数据*/
QNetworkReply*reply =manager.get(req);
/*阻塞loop请求:同步处理*/
QEventLoop eventLoop;
connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
ret = httpReply(reply);
(2)如果程序中http请求是异步的,则不能用临时的栈对象(如(1)),会导致http还没有回复的时候,manager对象因为函数的结束而销毁,进而connect函数永远都不会进来。有如下几种方法:
(2.1)每一次循环或者申请的时候,new一个对象,直接在函数结束的时候delete QNetworkAccessManager对象
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
/*设置http请求*/
QNetworkRequest req;
req.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json;charset=UTF-8"));
..........
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpReply(QNetworkReply*)));
/*将manager delete*/
connect(manager, SIGNAL(finished(QNetworkReply*)), manager, SLOT(deleteLater()));
/*get http 数据*/
QNetworkReply*reply =manager->get(req);
(2.2)一个应用程序只需要定义一个QNetworkAccessManager就行,没有必要每次循环都new一个。connect函数不能放在循环中,要在变量初始化后。
构造函数中
manager = new QNetworkAccessManager(this);//manager是成员变量
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpRepy(QNetworkReply*)));
for (int index = 0; index < 10; index++)
{
httpReq(ASYNC);
}
请求函数实现
int httpReq(unsigned char syncType)
{
int ret = 0;
/*设置http请求*/
QNetworkRequest req;
req.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json;charset=UTF-8"));
..........
/*get http 数据*/
QNetworkReply*reply =mapSyncManagerSta->get(mapSyncReq);
/*同步*/
if(SYNC == syncType)
{
/*阻塞loop请求:同步处理*/
QEventLoop eventLoop;
connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
}
return ret;
}