diff --git a/networkmonitorapplet.cpp b/networkmonitorapplet.cpp index db4ecae..3d7d3f1 100644 --- a/networkmonitorapplet.cpp +++ b/networkmonitorapplet.cpp @@ -110,6 +110,12 @@ QString NetworkMonitorApplet::ipAddress() const return m_ipAddress; } +// 返回活动接口的 IPv6 全球地址,供 QML 显示 +QString NetworkMonitorApplet::ipv6Address() const +{ + return m_ipv6Address; +} + void NetworkMonitorApplet::refresh() { readNetworkStats(); @@ -279,21 +285,30 @@ qint64 NetworkMonitorApplet::getActiveTxBytes() const return m_interfaces[m_activeInterface].txBytes; } -// 检测活动接口的 IPv4 地址 -// 跳过 IPv6 和 loopback,只取第一个有效 IPv4 地址 -// IP 变化时发射 ipAddressChanged 信号通知 QML 更新 -// 设计原因:DHCP 续约、网络切换等场景下 IP 可能变化,需持续检测 +// 检测活动接口的 IPv4 与 IPv6 地址 +// IPv4:跳过 loopback,取第一个 +// IPv6:跳过 loopback 和 link-local (fe80::),取第一个全球地址 +// 任一地址变化时分别 emit 对应信号通知 QML 更新 +// 设计原因:DHCP 续约、网络切换、IPv6 SLAAC 等场景下地址可能变化,需持续检测 void NetworkMonitorApplet::detectIpAddress() { QString newIp; + QString newIpv6; if (!m_activeInterface.isEmpty()) { QNetworkInterface iface = QNetworkInterface::interfaceFromName(m_activeInterface); for (const QNetworkAddressEntry &entry : iface.addressEntries()) { - // 只取 IPv4 地址,跳过 IPv6 和 loopback + // IPv4:跳过 loopback,取第一个 if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol - && !entry.ip().isLoopback()) { + && !entry.ip().isLoopback() + && newIp.isEmpty()) { newIp = entry.ip().toString(); - break; + } + // IPv6:跳过 loopback 和 link-local (fe80::),取第一个全球地址 + if (entry.ip().protocol() == QAbstractSocket::IPv6Protocol + && !entry.ip().isLoopback() + && !entry.ip().isLinkLocal() + && newIpv6.isEmpty()) { + newIpv6 = entry.ip().toString(); } } } @@ -301,6 +316,10 @@ void NetworkMonitorApplet::detectIpAddress() m_ipAddress = newIp; emit ipAddressChanged(); } + if (m_ipv6Address != newIpv6) { + m_ipv6Address = newIpv6; + emit ipv6AddressChanged(); + } } // 判断是否为物理网卡 diff --git a/networkmonitorapplet.h b/networkmonitorapplet.h index 1365b70..f7d095d 100644 --- a/networkmonitorapplet.h +++ b/networkmonitorapplet.h @@ -40,6 +40,8 @@ class NetworkMonitorApplet : public DApplet Q_PROPERTY(QString activeInterface READ activeInterface NOTIFY activeInterfaceChanged) // 活动接口的 IPv4 地址,供 QML 在弹出面板和 tooltip 中显示 Q_PROPERTY(QString ipAddress READ ipAddress NOTIFY ipAddressChanged) + // 活动接口的 IPv6 全球地址(已过滤 link-local 和 loopback),供 QML 显示 + Q_PROPERTY(QString ipv6Address READ ipv6Address NOTIFY ipv6AddressChanged) public: explicit NetworkMonitorApplet(QObject *parent = nullptr); @@ -57,6 +59,7 @@ public: bool ready() const; QString activeInterface() const; QString ipAddress() const; + QString ipv6Address() const; Q_INVOKABLE void refresh(); Q_INVOKABLE void setActiveInterface(const QString &interface); @@ -69,12 +72,13 @@ signals: void readyChanged(); void activeInterfaceChanged(); void ipAddressChanged(); + void ipv6AddressChanged(); private: void readNetworkStats(); void calculateSpeed(); void detectInterfaces(); - // 检测活动接口的 IPv4 地址,变化时发射 ipAddressChanged + // 检测活动接口的 IPv4 与 IPv6 地址,变化时分别发射对应信号 void detectIpAddress(); // 判断是否为物理网卡(无线 wlp/wlan,有线 enp/eth), // 用于自动选择时优先真实网卡而非虚拟代理接口(如 Meta/tun0) @@ -87,6 +91,7 @@ private: QStringList m_interfaceList; QString m_activeInterface; QString m_ipAddress; // 活动接口的 IPv4 地址 + QString m_ipv6Address; // 活动接口的 IPv6 全球地址(过滤 link-local) // 速度计算 qint64 m_lastRxBytes;