QHostInfo检测网络
阅读原文时间:2021年04月23日阅读:1

   平时,我们检测网络是否连接,一般都是用ping命令。实际开发中,经常也需要检测网络状态。最近之项目过程中就需要实现这一的功能,在网络断开时给出相应的用户提示。QHostInfo给我们提供了一个方便的接口,实现这一的功能。话不多说,先上一段代码demo

NetWorkTest *NetWorkTest::GetInstance()
{
    static NetWorkTest instance;
    return &instance;
}

void NetWorkTest::checkNetWork()
{
    QHostInfo::lookupHost("www.baidu.com",this,SLOT(lookedUpSlot(QHostInfo)));
    qDebug()<< "lookupHost";
}

NetWorkTest::NetWorkTest(QObject *parent) : QObject(parent)
{

}


void NetWorkTest::lookedUpSlot(QHostInfo hostInfo)
{
    qDebug()<<__FUNCTION__;
    bool status = false;
    if(hostInfo.error() == QHostInfo::NoError)
    {
        status = true;
    }
    emit netWorkStateChanged(status);
}


//main.cpp

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);


    QQmlContext *context=engine.rootContext();
    context->setContextProperty("netWorkTest", NetWorkTest::GetInstance());
    engine.load(url);

    return app.exec();
}

//main.qml
Window {
    visible: true
    width: 640
    height: 480
//    title: qsTr("Hello World")
    property bool connected: true//qsTr("网络已连接")
    RowLayout {
        id: layout
//        anchors.fill: parent
        width: 200
        anchors.centerIn: parent
        Button{
            text: qsTr("检测网络")
            onClicked: {
                netWorkTest.checkNetWork();
            }
        }
        Label{
            text: qsTr("网络状态:")
        }
        Label{
            id: status
            text: {
                if(connected)
                {
                    return qsTr("网络已连接")
                }
                else{
                    return qsTr("网络已断开")
                }
            }
        }
    }
    Connections{
        target: netWorkTest
        onNetWorkStateChanged:{
            console.log('isConnected: ',isConnected)
            connected = isConnected;
        }
    }

}

这样,基本实现我们需要的结果。但是,实际测试过程中发现,断开网络之后,再检测,还是返回true。着就让人纳闷。更郁闷的是,从QHostInfo的说明文档找不到任何相关的说明。个人猜测就是有缓存。要找到真正的原因,只能看QHostInfo的实现代码了。

int QHostInfo::lookupHost(const QString &name, QObject *receiver,
                          const char *member)
{
   //此处省略不重要的代码
    //以下才是我们要关注的核心代码
    QHostInfoLookupManager *manager = theHostInfoLookupManager();

    if (manager) {
        // the application is still alive
        if (manager->cache.isEnabled()) {
            // check cache first
            bool valid = false;
            QHostInfo info = manager->cache.get(name, &valid);
            if (valid) {
                if (!receiver)
                    return -1;

                info.setLookupId(id);
                QHostInfoResult result;
                QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
                result.emitResultsReady(info);
                return id;
            }
        }

        // cache is not enabled or it was not in the cache, do normal lookup
        QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id);
        if (receiver)
            QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
        manager->scheduleLookup(runnable);
    }
    return id;
}

如此,我们清楚QHostInfo确实三用了缓存。既然三缓存,我们有没有办法清除这些缓存呢。继续深入探讨源码:

// cache for 60 seconds
// cache 128 items
QHostInfoCache::QHostInfoCache() : max_age(60), enabled(true), cache(128)
{
#ifdef QT_QHOSTINFO_CACHE_DISABLED_BY_DEFAULT
    enabled = false;
#endif
}

bool QHostInfoCache::isEnabled()
{
    return enabled;
}

// this function is currently only used for the auto tests
// and not usable by public API
void QHostInfoCache::setEnabled(bool e)
{
    enabled = e;
}

看看这实现,显然是没办法了。没有对外的API可以清除缓存或者修改缓存过期时间。既然如此,想要解决这个问题,就只能自己实现ping操作了。

void pingHost(NetWorkTest* instance)
{
    QProcess exc;
    QTextCodec *codec = QTextCodec::codecForName("GBK");
    QString cmdstr="ping www.baidu.com";
    exc.start(cmdstr);
    exc.waitForFinished(-1);
    QString  outstr=codec->toUnicode(exc.readAll());
    qDebug()<<outstr;
    bool status = false;
    if((-1 !=outstr.indexOf("往返行程的估计时间")))
    {
      qDebug("在线\n");
      status = true;
    }
    emit instance->netWorkStateChanged(status);
}

void NetWorkTest::checkNetWork()
{

   QFuture<void> future = QtConcurrent::run(pingHost,this);
}

这里用到了QtConcurrent实现多线程,防止卡住界面。

https://github.com/huanghaining/NetWork

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章