QNetworkAccessManager get 超时等待引起的问题

编程入门 行业动态 更新时间:2024-10-07 12:27:38

QNetworkAccessManager get 超时等待引起的问题

QNetworkAccessManager get 超时等待引起的问题

前言

给用户写个小程序,用来访问和控制他们的设备。
他们设备在片上开了一个http服务器,用http get 方法取运行状态,用http post 方法控制设备动作。

现场运行后,在网络良好的情况下,发现不定时的会出现访问不到他们设备。有时是还能ping的通,但是访问不到。有时是ping不通,也访问不到。

这个设备是用户采购的第三方设备,用户咨询设备厂商,厂商说我的写程序有问题,让我看看我程序哪写错了。

我当时就怒了,就没听说过访问一个url,能将设备的通讯跑死的。
这大概率都是设备固件写的有问题,不是内存用光了,就是系统挂掉了,但是没有启用看门狗。

微信铁坨坨的厂商,要出厂测试程序,想测试一下设备的长期运行稳定性。厂商说,他们只作机械和电气部分,控制盒是外购的,控制盒厂商测试过了,所以没有出厂测试程序。

立刻有种不详之感涌上心头,这设备能运行的稳定么?自己都没测试过,居然说我程序写的有问题,这是啥逻辑…

没有经过老化的东西,居然就敢卖。

我们新品(不管是简单还是复杂)最少都要老化一个月,各种测试,确定软件硬件都没问题后,才会批量生产出货。

行,不是说我程序有问题么?那我来写个测试程序跑一下,到底是设备有问题,还是我程序写的挫。

让用户给我邮寄了一套第三方设备,有一个铁坨坨设备,一个控制盒,将铁坨坨设备和控制盒用控制电缆连好,将控制盒网口和路由接上,控制盒上电(220V),这时就可以http访问。

写了个测试程序,开始跑。
发现这个设备http回包的时间不定,有时可能需要几秒才有回包。这一看,设备固件程序写的就有问题。
哪有说http访问要那么长时间,不是来了http访问,做个标记,转圈查询标记,干完活才回包吧?

用QT实现http get/post, 网上代码都一样。不存在写的挫的问题。
看了一下,我http get/post时都带了超时值,但是我超时已经设置为6秒了。有时还是超时。
后来改成无超时,死等http回包,这下搞定。如果连接有效,但是设备无回答,默认超时是60秒。
我就很纳闷,这设备片上的http服务器实现的这么挫…

工程中用的 http get实现,网上资料来的,去掉了超时等待。

http get

void WorkerThread3::http_get_dev_status()
{msleep(6000); // 延时x秒再查询QString str_tmp;QString str_url;QNetworkReply::NetworkError err;QNetworkAccessManager *accessManager = new QNetworkAccessManager(this);QNetworkRequest request;str_url = QString(tr("http://%1/")).arg(/*"www.baidu"*/ this->m_str_url);request.setUrl(QUrl(str_url));// add Basic Authentication// YWRtaW46MTIzNDU3 is hash for my_usr:my_pwdrequest.setRawHeader("Authorization", "Basic YWRtaW46MTIzNDU3");//getQNetworkReply* rplay = accessManager->get(request);QEventLoop eventLoop;connect(accessManager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));eventLoop.exec();       //block until finishdo {err = rplay->error();// test - get special err sn's stringstr_tmp = QString(tr("network error : [%1] %2")).arg(err).arg(get_network_err_string(QNetworkReply::RemoteHostClosedError));// "network error : [0] RemoteHostClosedError"if (QNetworkReply::NoError != err) {// 只有不设置超时,等accessManager完成后,才会带真正的错误码回来str_tmp = QString(tr("network error : [%1] %2")).arg(err).arg(get_network_err_string(err));// "network error : [99] UnknownNetworkError"show_ui_msg_and_log(str_tmp);return;}QByteArray rd_buf = rplay->readAll();str_tmp.clear();// 如果accessManager没有正常完成,错误码还是QNetworkReply::NoError// 所以要判断一下回包if (rd_buf.length() <= 0) {str_tmp = QString(tr("error : http get [%1]").arg(request.url().toString()));show_ui_msg_and_log(str_tmp);// return; // debug only}// use recv packagestr_tmp.append(rd_buf);show_ui_msg_and_log(str_tmp); // now only show it// 注释代码的快捷键// CTRL + /rd_buf = str_tmp.toUtf8(); // 将字符串转成数组parse_replay_as_json(rd_buf);} while (0);if (NULL != rplay) {rplay->deleteLater(); //销毁请求对象}if (NULL != accessManager) {delete accessManager;accessManager = NULL;}
}

http post

bool WorkerThread3::http_post_to_dev(int i_dev_stat)
{QString str_tmp;int i_switch_to = (0 == i_dev3_main_backup_stat) ? 1 : 0;QNetworkReply::NetworkError err;QNetworkAccessManager *accessManager = new QNetworkAccessManager(this);msleep(6000); // 睡x秒,再postQNetworkRequest request;char sz_buf[0x40] = {'\0'};itoa(i_switch_to, sz_buf, 10);QString str = QString(QLatin1String(sz_buf));QString str_url = QString(tr("http://%1%2")).arg(/*"www.baidu"*/ this->m_str_url).arg(tr("/gpio/dout/1"));// str_url += str;QUrl url(str_url);QByteArray data;if (1 == i_switch_to) {data.append(tr("1"));} else {data.append(tr("0"));}request.setUrl(url);// add Basic Authentication// YWRtaW46MTIzNDU3 is hash for my_user:my_pwdrequest.setRawHeader("Authorization", "Basic YWRtaW46MTIzNDU3");request.setRawHeader("content-type","application/x-www-form-urlencoded");QNetworkReply* rplay = accessManager->post(request, data);QEventLoop eventLoop;connect(accessManager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));eventLoop.exec();       //block until finishdo {err = rplay->error();// test - get special err sn's stringstr_tmp = QString(tr("network error : [%1] %2")).arg(err).arg(get_network_err_string(QNetworkReply::RemoteHostClosedError));// "network error : [0] RemoteHostClosedError"if (QNetworkReply::NoError != err) {// 只有不设置超时,等accessManager完成后,才会带真正的错误码回来str_tmp = QString(tr("network error : [%1] %2")).arg(err).arg(get_network_err_string(err));// "network error : [99] UnknownNetworkError"show_ui_msg_and_log(str_tmp);// log_msg_to_file(DEBUG_SWITCH_ABOUT_LOG_FILE_NAME, QString("err1 = %1").arg(str_tmp));return false;}QByteArray rd_buf = rplay->readAll();// 如果accessManager没有正常完成,错误码还是QNetworkReply::NoError// 所以要判断一下回包if (rd_buf.length() <= 0) {str_tmp.clear();str_tmp = QString(tr("info no recv packge : http post [%1]").arg(request.url().toString()));show_ui_msg_and_log(str_tmp);// return false; // debug only} else {str_tmp = QString::fromUtf8(rd_buf.data(),rd_buf.length());show_ui_msg_and_log(QString("info recv packge, rd_buf.length() = %1, rd_buf = %2").arg(rd_buf.length()).arg(str_tmp));}str_tmp.clear();str_tmp.append(rd_buf);show_ui_msg_and_log(str_tmp); // now only show it// 即使有回包,好像也不需要分析了} while (0);if (NULL != rplay) {rplay->deleteLater(); //销毁请求对象}if (NULL != accessManager) {delete accessManager;accessManager = NULL;}show_ui_msg_and_log(QString("http_post_to_dev ok"));return true;
}

测试情况

因为程序确实有改进,就以为是自己写的不对,没死等人家回包啊,我的不对。
开始跑测试程序,准备跑个3天,如果没问题,就更新程序,将http操作,都换成无超时的。
看着跑了1500次,很正常,这不挺好么?不理他了,开始干别的,然后睡觉。
控制设备的时候,有机械动作,能听见响,知道设备很正常。
早上醒了,赖在床上听了一会,不对劲…
我是查询100次设备,操作设备一次,也就是5~10分钟,我就能听到操作设备时的机械动作的声音。
为啥等着这么久,都没听见响?

起床,用远程桌面连到笔记本上,看到测试程序界面上打印出报错信息(错误号转过来的文本)。
每60秒一条错误信息,已经http get 不到设备了。

此时正常查询设备了5000次,切换了50次。看日志时间,从夜里2:30开始就访问不到设备了。程序跑的时候是15:00, 设备正常运行时间才不到12个小时。

用windows命令行自带的ping 去ping设备,ping不通,cao!
开始给客户写测试报告,说明设备长期运行稳定性确实不行,已经用实验证明了设备固件有问题,别赖我了。

将测试报告,测试程序,测试程序使用说明都给了客户。让用户给厂商,让厂商用我提供的测试程序跑他们设备,如果能通过测试程序的长期测试,再让产商更新现场的设备固件。

后续的好奇心

开始写测试程序时,我就有点纳闷,这设备的http操作怎么响应的这么慢…

我们自己设备上也有片上http服务器,没这么慢啊,来了http get, 从内存里拿个数,拼好包回发。来了http post, 将操作值放在内存中,回包。干完http post要求的活,更新内存值,说明操作结果。这不都是ms级别的http回包么?

将用户邮来的铁坨坨控制盒拆开了。看看里面硬件大概啥样子?
外壳是x宝上常见的铝型材,将两边堵头打开,看到电路板了。
这插座,指示灯啥的咋都没怼到板子上,就那么焊接了, 元件离电路板都有1~3mm的距离。第一感觉,这板子糙啊。

220V进来,有1块带变压器的小板,将电转成5~48V的多路,给MCU和铁坨坨用。
MCU是Atmega328P AU,arduino开发板常用的MCU.
MCU控制ENC28J60 + RJ45网座,作为网络通讯。
还有2个继电器,一个是开关量输入检测,一个是开关量输出控制铁坨坨设备。
感觉问题出在这个MCU固件编程上了。

这个MCU编译环境一般是arduino专用的IDE, 这种IDE用C编程的,库都封好了,对MCU的控制粒度没那么细。上网大概看了一下,这种IDE, 函数都写好了,你往里面填实现就行。arduino专用的IDE自带的例程都有http服务器实现,去github上看, Atmega328P AU + ENC28J60有工程。不至于是arduino封装的底层库有问题吧?

咱也没玩过arduino,没啥发言权。以后有时间玩玩。
反正这个控制盒长期运行不稳定(http 会将设备跑死)的问题, 一定是MCU(Atmega328P AU)固件编程写的挫的缘故。

看板子上的制版日期,2014还是2016年的板子,谁知道他们卖了这么久,就没有人反应过这个问题?我打死都不信。

我要是玩几天arduino,写个相同功能(http片上服务器),也不至于写的这么挫…

跟领导说了,如果有量,有钱拿,咱们对标他,出个控制盒。不过我们产品上就有片上http服务器,我会换成我们产品成熟的软硬件。除了MCU和网卡芯片之外的硬件实现,参考这个控制盒的。

更多推荐

QNetworkAccessManager get 超时等待引起的问题

本文发布于:2024-02-16 18:06:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1690999.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:QNetworkAccessManager

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!