作者:我叫博小微 | 来源:互联网 | 2023-09-01 14:45
背景项目交互中,经常要用到websocket,http与服务器通信,但是网络情况又没法保证,网络可能一会是链接状态,一会是断开状态,所以需要有能力实时去检测网络状态;传统方法,或者
背景
项目交互中,经常要用到websocket,http与服务器通信,但是网络情况又没法保证,网络可能一会是链接状态,一会是断开状态,所以需要有能力实时去检测网络状态;传统方法,或者要求行不高的情况下,大多采取程序中单独去个线程,去定时获取外网是否联通。但在商业项目中,尤其是toc的行业,这种网络检测一定要稳定、靠谱,不然直接会给商品大打折扣。
本项目,刚开始也是采用了传统的方法开个网络检测线程,但后来跟人沟通,这种方法不适合,比如在电脑端,如果10个程序都需要联网呢?难道需要10个app都要开线程去检测嘛。所以,网络检测应该时系统层面链路层的东西。
下面简单介绍下传统检测的两种方法,直接给代码了!
使用QNetworkAccessManager / post
.h
class NetLiveWorker : public QObject
{
Q_OBJECT
public:
explicit NetLiveWorker(QObject *parent = nullptr);
~NetLiveWorker();
Q_INVOKABLE bool getLive(){return m_isLive;}
Q_INVOKABLE bool IsHostOnline(QString strHostName, int nTimeoutmSecOnds= 2000);
bool IsWebOk();
signals:
void sig_netChanged(bool);
public slots:
void onTimeout();
private:
bool m_isLive;
bool m_isFirst;
QNetworkAccessManager *pmanager;
};
.cpp
NetLiveWorker::NetLiveWorker(QObject *parent) : QObject(parent)
{
m_isFirst = true;
m_isLive = false;
pmanager = new QNetworkAccessManager(this);
}
NetLiveWorker::~NetLiveWorker()
{
if(pmanager)
delete pmanager;
pmanager = NULL;
}
bool NetLiveWorker::IsWebOk()
{
//return IsHostOnline("110.242.68.4", 2000);
return IsHostOnline("https://www.baidu.com/", 3000);
}
void NetLiveWorker::onTimeout()
{
bool islive = IsWebOk();
//qDebug()<<"Worker::onTimeout islive =" < if(m_isLive != islive || m_isFirst)
{
emit sig_netChanged(islive);
}
m_isLive = islive;
m_isFirst = false;
//qDebug()<<"Worker::onTimeout get called from : "<}
bool NetLiveWorker::IsHostOnline(QString strHostName, int nTimeoutmSeconds)
{
QNetworkRequest request(strHostName);
request.setRawHeader("Content-Type", "charset='utf-8'");
request.setRawHeader("Content-Type", "application/json");
QEventLoop eventloop;
QTimer timer;
timer.singleShot(nTimeoutmSeconds, &eventloop, SLOT(quit()));
timer.start();
QNetworkReply* reply = pmanager->get(request);
QMetaObject::Connection cOnRet= QObject::connect(reply, SIGNAL(finished()), &eventloop, SLOT(quit()));
Q_ASSERT(conRet);
eventloop.exec(QEventLoop::ExcludeUserInputEvents);
if (!timer.isActive())
{
//超时,未知状态
QObject::disconnect(reply, SIGNAL(finished()), &eventloop, SLOT(quit()));
reply->abort();
reply->deleteLater();
return false;
}
if (reply->error() != QNetworkReply::NoError)
{
//qDebug() <<"error = " <error();
reply->abort();
reply->deleteLater();
return false;
}
bool bRes = reply->readAll().length() > 0;
reply->abort();
reply->deleteLater();
return bRes;
}
使用getlive方法即可拿到当前外网状态。
ping命令实现
.h
class NetworkDetect : public QThread
{
Q_OBJECT
public:
NetworkDetect();
virtual void run();
void stop();
signals:
void sig_netStatusChanged(bool state);
private:
bool flagRunning; //线程运行标志
QProcess *network_process;
};
.cpp
NetworkDetect::NetworkDetect()
{
flagRunning = true;
}
void NetworkDetect::run()
{
QString network_cmd = "ping www.baidu.com -w 500 -n 2";
QString result;
network_process = new QProcess(); //不要加this
while(flagRunning)
{
network_process->start(network_cmd); //调用ping 指令
network_process->waitForFinished(); //等待指令执行完毕
result = network_process->readAll(); //获取指令执行结果
//qDebug() < if(result.contains(QString("TTL=")) || result.contains(QString("ttl="))) //若包含TTL=字符串则认为网络在线
{
emit sig_netStatusChanged(true); //在线
}
else
{
emit sig_netStatusChanged(false); //离线
}
sleep(1); //加sleep降低CPU占用率
}
}
void NetworkDetect::stop()
{
flagRunning = false;
}
不同平台下ping命令的参数不一样,可通过 ping --help来参考
扩展
在某些嵌入式平台下,应该时系统层面通过回调函数来告诉你外网是否联通,有种wifi情况下,即使通知你链接成功了,也未必能通外网,还是需要你通过portalAuth机制来检测下。即拿到网络链路成功后,通过http或者ping方法确实是否能连外网。
Portal认证简介
Portal认证通常也称为Web认证,一般将Portal认证网站称为门户网站。用户上网时,必须在门户网站进行认证,只有认证通过后才可以使用网络资源。
用户可以主动访问已知的Portal认证网站,输入用户名和密码进行认证,这种开始Portal认证的方式称作主动认证。反之,如果用户试图通过HTTP访问其他外网,将被强制访问Portal认证网站,从而开始Portal认证过程,这种方式称作强制认证。
内置portal认证---------指的就是会话认证。
外置Portal认证