QNetworkConfigurationManager 与网络状态监控:Qt 上位机如何判断网络真的可用

做 Qt 上位机,网络通信经常会遇到一个看起来很简单、实际非常麻烦的问题:

网线插着,就代表网络可用吗?

当然不是。工业现场可能出现:

  • 网线被拔掉

  • Wi-Fi 断开

  • 网卡被禁用

  • IP 地址发生变化

  • DHCP 重新分配地址

  • 路由器异常

  • 局域网正常,但服务器连接不上

  • 网络恢复以后,原来的 TCP 连接已经失效

如果程序只是启动时判断一次网络状态,运行几个小时以后基本就不可靠了。

Qt 5 中,QNetworkConfigurationManager 曾经是网络配置和 Bearer 状态管理的重要 API;而在 Qt 6 中,这套 Bearer Management 已经移除,官方提供了新的 QNetworkInformation。

所以今天这篇文章,我们把两套方案一起讲清楚。

一、先搞清楚:网络状态到底是什么?

很多程序喜欢写:

cpp 复制代码
if (networkAvailable) {
    sendData();
}

问题是:networkAvailable 到底代表什么?

至少可以拆成四层:

例如:

每一层都正常,才是真正意义上的"业务网络可用"。

所以网络状态监控不能简单理解成:

"有没有网卡?"

而应该理解成:

当前网络连接处于什么状态,以及我的业务是否还能正常通信。


二、Qt 5:QNetworkConfigurationManager

在 Qt 5 中:

复制代码
#include <QNetworkConfigurationManager>

核心对象就是:

复制代码
QNetworkConfigurationManager manager;

它可以用来查询当前系统中的网络配置,并监听配置变化。

常见 API 包括:

  • allConfigurations() 返回所有符合指定状态标志的网络配置。状态标志可以是如"已启用"(Active)、"可用"(Discovered)等。

  • defaultConfiguration() 返回当前的默认网络配置。默认配置通常是系统当前使用的网络配置。

  • configurationFromIdentifier()

  • capabilities()

同时还有几个非常重要的信号:

  • configurationAdded()

  • configurationRemoved() 当某个网络配置被移除时发出此信号。可以用来处理配置被删除的情况。

  • configurationChanged() 当某个网络配置发生变化时发出此信号。这个信号可以用于监控某个特定的网络配置。

  • **void onlineStateChanged(bool isOnline)**当系统的在线状态发生变化时发出此信号。如果系统从离线切换到在线,或反之,会发出该信号。

例如:

cpp 复制代码
QNetworkConfigurationManager *manager =
        new QNetworkConfigurationManager(this);

connect(manager,
        &QNetworkConfigurationManager::configurationChanged,
        this,
        []() {
            qDebug() << "Network configuration changed";
        });

这样,当系统网络配置发生变化时,程序就可以得到通知。


三、不要把"配置变化"当成"网络断开"

这是使用 QNetworkConfigurationManager 时最容易犯的错误。

例如:

这个信号表达的是:

网络配置发生了变化。

它并不严格等价于:

服务器已经连接不上了。

同样,configurationChanged() 也不代表 TCP 连接一定断开,更不能直接写成:

cpp 复制代码
connect(manager,
        &QNetworkConfigurationManager::configurationChanged,
        this,
        &NetworkManager::disconnectFromServer);

这种设计非常危险。

更合理的结构应该是:

网络配置只是输入条件之一。


四、Qt 5 中一个典型的监控器

可以把网络状态统一封装成一个类:

cpp 复制代码
class NetworkMonitor : public QObject
{
    Q_OBJECT

public:
    explicit NetworkMonitor(QObject *parent = nullptr);

signals:
    void networkChanged(bool available);

private slots:
    void onConfigurationChanged(
        const QNetworkConfiguration &config);

private:
    QNetworkConfigurationManager *m_manager;
};

初始化:

cpp 复制代码
NetworkMonitor::NetworkMonitor(QObject *parent)
    : QObject(parent)
{
    m_manager =
        new QNetworkConfigurationManager(this);

    connect(m_manager,
            &QNetworkConfigurationManager::configurationChanged,
            this,
            &NetworkMonitor::onConfigurationChanged);
}

然后根据当前配置重新判断状态。

不过这里有一个关键问题:

不要只依赖系统状态。


五、为什么"网络已连接"仍然可能访问不了服务器?

举一个工业现场非常典型的场景:

此时:

  • 网卡:正常

  • IP:正常

  • 网关:正常

  • 局域网:正常

但是:

Server: 192.168.1.100:8080 已经挂掉了。

此时操作系统可能仍然认为网络在线,但你的业务实际上已经无法通信。

所以:

系统网络状态 ≠ 业务网络状态。

这是网络监控设计中最重要的一条原则。


六、正确做法:系统状态 + 业务探活

工业 Qt 程序建议设计两层监控:

例如定义:

cpp 复制代码
enum class NetworkState
{
    Unknown,
    Offline,
    Connecting,
    Online,
    Degraded
};

这样比一个 bool networkAvailable; 强很多。


七、Qt 6:QNetworkInformation

如果项目使用 Qt 6,就不要再围绕 QNetworkConfigurationManager 设计新代码。

Qt 6 提供:

复制代码
#include <QNetworkInformation>

官方 API 从 Qt 6.1 开始提供网络相关信息。它支持网络可达性、传输介质、计费网络、Captive Portal 等能力。

最核心的是 QNetworkInformation::Reachability,包括:

  • Unknown

  • Disconnected

  • Local

  • Site

  • Online

也就是说,Qt 6 对网络状态的表达更加接近:

复制代码
Disconnected → Local → Site → Online

而不是简单的 true / false。


八、Qt 6 网络状态监控实战

首先加载默认 Backend:

复制代码
QNetworkInformation::loadDefaultBackend();

然后获取实例:

复制代码
auto *info = QNetworkInformation::instance();

读取当前状态:​​​​​​​

cpp 复制代码
auto state = info->reachability();

if (state ==
    QNetworkInformation::Reachability::Online) {

    qDebug() << "Network online";
}

更重要的是监听:​​​​​​​

cpp 复制代码
connect(info,
        &QNetworkInformation::reachabilityChanged,
        this,
        [](QNetworkInformation::Reachability state) {

    qDebug() << "Reachability changed:"
             << static_cast<int>(state);
});

这样网络发生变化时,应用可以及时响应。


九、Qt 6 还能判断当前网络介质

从 Qt 6.3 开始,还可以获取 transportMedium():

复制代码
auto medium = info->transportMedium();

可能得到:

  • Ethernet

  • WiFi

  • Cellular

  • Bluetooth

  • Unknown

于是工业软件可以进一步区分:​​​​​​​

复制代码
Ethernet  → 工业设备通信
Wi-Fi     → 普通业务通信
​​​​​​​​​​​​​​Cellular  → 远程维护 / 云端通信

官方文档也说明,当用户拔掉网线、离开 Wi-Fi 范围或开启飞行模式时,传输介质发生变化会触发对应信号。


十、网络监控不要直接控制业务

一个常见的错误架构:

这样很容易产生大量状态竞争。

更推荐:​​​​​​​

cpp 复制代码
               NetworkMonitor
                     │
                     ▼
                NetworkState
                     │
                     ▼
              ConnectionManager
                     │
        ┌────────────┼────────────┐
        ▼            ▼            ▼
      TCP            HTTP         MQTT
        │            │            │
        └────────────┼────────────┘
                     ▼
                BusinessService

也就是说:

  • NetworkMonitor 负责"观察"

  • ConnectionManager 负责"连接"

  • 职责不要混在一起


十一、工业项目推荐:状态机管理网络连接

如果是 7×24 小时运行的 Qt 上位机,可以进一步设计状态机:​​​​​​​

cpp 复制代码
                ┌─────────────┐
                │    Init     │
                └──────┬──────┘
                       ▼
                ┌─────────────┐
                │ Disconnected│
                └──────┬──────┘
                       │ network available
                       ▼
                ┌─────────────┐
                │ Connecting  │
                └──────┬──────┘
                       │ success
                       ▼
                ┌─────────────┐
                │   Online    │
                └──────┬──────┘
                       │ error
                       ▼
                ┌─────────────┐
                │ Reconnecting│
                └──────┬──────┘
                       │
                       └──────────► Connecting

再增加业务探活:​​​​​​​

cpp 复制代码
Online
  │
  │ heartbeat timeout
  ▼
Degraded
  │
  │ recover
  ▼
Online

这样网络系统就不再是简单的 if (connected),而是一个真正的连接生命周期。


十二、心跳比"判断网络在线"更可靠

例如 TCP 长连接,使用 QTimer *heartbeatTimer; 周期性发送:

cpp 复制代码
Heartbeat → Server → Heartbeat ACK

如果发送成功 + 收到 ACK,才能认为业务连接正常。

如果连续三次没有响应:​​​​​​​

bash 复制代码
Heartbeat
Heartbeat
Heartbeat
   ↓
Timeout
   ↓
Disconnected
   ↓
Reconnect

这比单纯判断 QNetworkInformation::Reachability::Online 更加接近真实业务状态。

Qt 官方也特别提醒,QNetworkInformation::reachability() 是基于操作系统 / Backend 的判断,在某些情况下可能并不准确,因此不应该把它作为连接服务器前的绝对"预检查"。


十三、最终推荐的 Qt 上位机架构

如果是工业通信软件,我更推荐把网络模块设计成:​​​​​​​

cpp 复制代码
                     MainWindow
                         │
                         ▼
                 Application Layer
                         │
                         ▼
                NetworkManager
                         │
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
   NetworkMonitor   ConnectionMgr   Heartbeat
          │              │              │
          ▼              ▼              ▼
 QNetworkInformation   TCP/HTTP       Timer
      / Qt5 QNCM
          │              │              │
          └──────────────┼──────────────┘
                         ▼
                  NetworkState
                         │
              ┌──────────┼──────────┐
              ▼          ▼          ▼
            Online    Degraded    Offline
              │
              ▼
          BusinessService
              │
        ┌─────┴─────┐
        ▼           ▼
       PLC         Server

这里有一个非常重要的设计思想:

网络状态监控是基础设施,不应该直接侵入业务代码。

业务层只关心:

  • Online

  • Offline

  • Degraded

而不需要到处写 QNetworkConfigurationManager 或者 QNetworkInformation。


十四、Qt 5 和 Qt 6 到底怎么选?

可以简单对比:

项目 Qt 5 Qt 6
网络配置 QNetworkConfigurationManager QNetworkInformation
Bearer Management 有 已移除
网络可达性 间接判断 Reachability
Wi-Fi / Ethernet QNetworkConfiguration TransportMedium
新项目 不建议继续依赖 推荐
老项目 可以继续维护 建议逐步迁移

Qt 6 官方已经移除了 QNetworkConfigurationManager 体系,因此如果现在开始设计新的 Qt 6 工业项目,建议直接以 QNetworkInformation + QNetworkInterface + QTcpSocket/QNetworkAccessManager 为基础。


十五、最后总结

QNetworkConfigurationManager 解决的是 Qt 5 时代的网络配置与 Bearer 状态管理问题。

但真正可靠的网络监控,不能只看一个 API。

应该分成三层:​​​​​​​

复制代码
第一层:系统网络  ──►  网卡 / IP / Wi-Fi / Ethernet       ↓第二层:网络可达性 ──►  Local / Site / Online       ↓第三层:业务连接  ──►  TCP / HTTP / 心跳 / ACK

最终得到:​​​​​​​

复制代码
系统在线 + 业务可达 + 心跳正常  ⇒  真正 Online
系统在线 + 服务器连接失败     ⇒  Degraded

而不是简单地认为"系统在线 = 业务在线"。

这也是 Qt 工业上位机网络模块从"能用"走向"稳定"的一个关键变化。

对于新项目,优先考虑 Qt 6 的 QNetworkInformation;对于 Qt 5 老项目,QNetworkConfigurationManager 仍然可以作为现有代码的网络配置监控手段,但最好把它封装在 NetworkMonitor 后面,为后续迁移到 Qt 6 留出接口。

Qt 6.8 官方文档目前也将 QNetworkInformation 作为 Qt Network 中的网络信息接口。

相关推荐
隐擎fox1 小时前
深入 QUIC 与 HTTP/3 协议栈特征:新一代 UDP 流量风控识别与网络防关联工程实战
网络·http·udp
碧海银沙音频科技研究院1 小时前
基于炬芯ATS3089X U 盘 MP3 播放器实现
网络
FW-Linker2 小时前
多链路聚合如何降低直播音画不同步概率?从网络抖动到数据包级拆分
网络·5g·智能路由器
逐梦之程2 小时前
EXCEL与DBC格式互转软件
运维·服务器·网络
重生之高冷汉堡包2 小时前
什么是数据中心代理?原理拆解、类型区别、应用场景与选型指南
服务器·网络·数据库·安全·ip
青衫客362 小时前
从网卡到 Socket:再探 Linux 网络协议栈与 iptables 数据包处理流程
linux·网络·网络协议
承渊政道2 小时前
Linux网络学习【TCP Socket编程实战:connect的断线重连与客户端访问Linux验证】
linux·网络·学习·ubuntu·tcp·socket编程
崽崽..2 小时前
【Linux】网络编程的调试工具以及连接失败的具体排查方法
linux·网络