// SPDX-FileCopyrightText: 2024 MyCompany // // SPDX-License-Identifier: LGPL-3.0-or-later #include "networkmonitorapplet.h" #include #include #include #include #include #include DS_BEGIN_NAMESPACE NetworkMonitorApplet::NetworkMonitorApplet(QObject *parent) : DApplet(parent) , m_refreshTimer(nullptr) , m_lastRxBytes(0) , m_lastTxBytes(0) , m_downloadSpeed(0) , m_uploadSpeed(0) , m_totalDownload(0) , m_totalUpload(0) , m_ready(false) , m_firstUpdate(true) { } NetworkMonitorApplet::~NetworkMonitorApplet() { } bool NetworkMonitorApplet::load() { return DApplet::load(); } bool NetworkMonitorApplet::init() { detectInterfaces(); // 启动定时刷新 m_refreshTimer = new QTimer(this); connect(m_refreshTimer, &QTimer::timeout, this, &NetworkMonitorApplet::refresh); m_refreshTimer->start(1000); // 每秒刷新一次 // 初始读取 readNetworkStats(); return DApplet::init(); } double NetworkMonitorApplet::downloadSpeed() const { return static_cast(m_downloadSpeed); } double NetworkMonitorApplet::uploadSpeed() const { return static_cast(m_uploadSpeed); } double NetworkMonitorApplet::totalDownload() const { return static_cast(m_totalDownload); } double NetworkMonitorApplet::totalUpload() const { return static_cast(m_totalUpload); } QStringList NetworkMonitorApplet::networkInterfaces() const { return m_interfaceList; } QStringList NetworkMonitorApplet::interfaceStats() const { QStringList stats; for (const QString &name : m_interfaceList) { if (m_interfaces.contains(name)) { const NetworkInterface &iface = m_interfaces[name]; stats << QString("%1|%2|%3|%4|%5") .arg(iface.name) .arg(iface.rxBytes) .arg(iface.txBytes) .arg(iface.rxPackets) .arg(iface.txPackets); } } return stats; } bool NetworkMonitorApplet::ready() const { return m_ready; } QString NetworkMonitorApplet::activeInterface() const { return m_activeInterface; } void NetworkMonitorApplet::refresh() { readNetworkStats(); } void NetworkMonitorApplet::setActiveInterface(const QString &interface) { if (m_activeInterface != interface) { m_activeInterface = interface; m_firstUpdate = true; emit activeInterfaceChanged(); } } void NetworkMonitorApplet::readNetworkStats() { QFile file("/proc/net/dev"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Failed to open /proc/net/dev"; return; } QTextStream stream(&file); QStringList lines = stream.readAll().split('\n', Qt::SkipEmptyParts); file.close(); QMap newInterfaces; // 跳过前两行标题 for (int i = 2; i < lines.size(); ++i) { QString line = lines[i].trimmed(); if (line.isEmpty()) continue; // 格式: "interface: rx_bytes rx_packets rx_errors rx_dropped ... tx_bytes tx_packets tx_errors tx_dropped ..." QRegularExpression re("^([^:]+):\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+\\d+\\s+\\d+\\s+\\d+\\s+\\d+\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)"); QRegularExpressionMatch match = re.match(line); if (match.hasMatch()) { NetworkInterface iface; iface.name = match.captured(1); iface.rxBytes = match.captured(2).toLongLong(); iface.rxPackets = match.captured(3).toLongLong(); iface.rxErrors = match.captured(4).toLongLong(); iface.rxDropped = match.captured(5).toLongLong(); iface.txBytes = match.captured(6).toLongLong(); iface.txPackets = match.captured(7).toLongLong(); iface.txErrors = match.captured(8).toLongLong(); iface.txDropped = match.captured(9).toLongLong(); // 过滤掉回环接口和虚拟接口 if (iface.name != "lo" && !iface.name.startsWith("veth") && !iface.name.startsWith("docker") && !iface.name.startsWith("br-")) { newInterfaces[iface.name] = iface; } } } // 检测接口变化 if (newInterfaces.keys() != m_interfaces.keys()) { m_interfaceList = newInterfaces.keys(); m_interfaces = newInterfaces; // 自动选择活动接口 if (m_activeInterface.isEmpty() && !m_interfaceList.isEmpty()) { // 优先选择有流量的接口 for (const QString &name : m_interfaceList) { const NetworkInterface &iface = m_interfaces[name]; if (iface.rxBytes > 0 || iface.txBytes > 0) { m_activeInterface = name; break; } } if (m_activeInterface.isEmpty()) { m_activeInterface = m_interfaceList.first(); } emit activeInterfaceChanged(); } m_ready = !m_interfaceList.isEmpty(); emit interfacesChanged(); emit readyChanged(); } else { m_interfaces = newInterfaces; } calculateSpeed(); emit statsChanged(); } void NetworkMonitorApplet::calculateSpeed() { qint64 currentRxBytes = getActiveRxBytes(); qint64 currentTxBytes = getActiveTxBytes(); if (m_firstUpdate) { m_firstUpdate = false; m_lastRxBytes = currentRxBytes; m_lastTxBytes = currentTxBytes; return; } // 计算速度(字节/秒) m_downloadSpeed = currentRxBytes - m_lastRxBytes; m_uploadSpeed = currentTxBytes - m_lastTxBytes; // 更新总量 m_totalDownload = currentRxBytes; m_totalUpload = currentTxBytes; m_lastRxBytes = currentRxBytes; m_lastTxBytes = currentTxBytes; emit speedChanged(); emit totalChanged(); } void NetworkMonitorApplet::detectInterfaces() { QDir sysClass("/sys/class/net"); if (!sysClass.exists()) return; QStringList entries = sysClass.entryList(QDir::Dirs | QDir::NoDotAndDotDot); m_interfaceList.clear(); for (const QString &entry : entries) { // 过滤回环接口 if (entry != "lo") { m_interfaceList << entry; } } m_ready = !m_interfaceList.isEmpty(); emit interfacesChanged(); emit readyChanged(); } qint64 NetworkMonitorApplet::getActiveRxBytes() const { if (m_activeInterface.isEmpty() || !m_interfaces.contains(m_activeInterface)) { return 0; } return m_interfaces[m_activeInterface].rxBytes; } qint64 NetworkMonitorApplet::getActiveTxBytes() const { if (m_activeInterface.isEmpty() || !m_interfaces.contains(m_activeInterface)) { return 0; } return m_interfaces[m_activeInterface].txBytes; } D_APPLET_CLASS(NetworkMonitorApplet) DS_END_NAMESPACE #include "networkmonitorapplet.moc"