Qt获取网页数据方法与经验总结

三个头文件:

#include 
#include 
#include 

基础理论知识:
QNetworkRequest 类用于表示网络请求,它也充当一个与请求信息相关的通用容器,例如:任何头信息和使用的加密相关的信息。当一个 request 对象被构造时,指定的 URL 决定所用的协议。目前 HTTP、FTP 和本地文件 URLs 支持上传和下载。

QNetworkAccessManager 类用于协调网络操作,一旦创建一个 request,该类用来发出请求并发射信号来报告它的进度。manager 也协调 cookies 的使用在 client 存储数据、请求的身份验证、代理的使用。

QNetworkReply 类用于网络请求的响应,当一个 request 被发出后,QNetworkAccessManager 就会创建相应的响应,通过 QNetworkReply 提供的信号可以单独监听每个响应,或者使用 manager 的信号。由于 QNetworkReply 是 QIODevice 的一个子类,可以同步或异步处理响应;也就是说,阻塞或非阻塞操作。

每个应用程序或库都可以创建一个或多个 QNetworkAccessManager 实例来处理网络通信。
参考链接:https://blog.csdn.net/rl529014/article/details/52878443
用上述博客的方法,执行一次网络请求没有任何问题,但我当时的程序是多次循环进行网络请求:
我将下面的代码放在了一个定时器的信号槽里面,定时器每秒触发一次:

    m_NetManger = new QNetworkAccessManager;  
    QUrl url("http://www.suse.edu.cn/");  

    m_Reply = m_NetManger->get(QNetworkRequest(url));  

    QObject::connect(m_NetManger, SIGNAL(finished(QNetworkReply*)),  
                     this, SLOT(finishedSlot(QNetworkReply*)));  

每十分钟,程序准时报错:

QThread::start: Failed to create thread(访问码无效。) 

当时很惊诧,明明是一个单线程程序啊!
研究之后发现,HTTP内部本身就使用了线程,我猜想是因为我每秒new一个QNetworkAccessManager,在HTTP内部就每秒创建一个线程,10分钟创建了600个,造成线程池溢出。

后来我将这句代码放在了构造函数里面: m_Reply = m_NetManger->get(QNetworkRequest(url));
程序运行,立马报错: Invalid parameter passed to C runtime function.
这个错误的原因一般都是调用函数的时候传递了空指针
但我输出两个指针的值,发现都不是空的,难道是m_Reply = m_NetManger->get(QNetworkRequest(url));
必须放在成员函数里面?好吧,我在new QNetworkRequest之前进行判断m_NetManger是否为空,避免多次new,结果还是提示Invalid parameter passed to C runtime function.

焦灼了很久,在大神的帮助下,更改了信号槽:
原信号槽:

connect(m_NetManger, SIGNAL(finished(QNetworkReply*)),  
                     this, SLOT(finishedSlot(QNetworkReply*))); 

更改之后的信号槽:

connect(m_Reply,SIGNAL(readyRead()),this,SLOT(finishedSlot()));

之后程序就运行正常了,原因:
networkAccessManager 是多线程的,每次request 就给你返回一个reply,由于网络访问的延时,在响应的槽里面的reply,到底是第一次request的,还是第二次的,甚至第三次的无法确定, 当你响应一个槽,deletelater后,接着又来一个reply,你原先的reply已经释放了,就是一个空指针,因此造成上述错误。

哦,对了,如果是像我一样没有给NetManger设置父对象以自动回收空间,别忘了在构造函数里面delete m_NetManger

你可能感兴趣的:(QT,Qt之路)