המטרה הייתה לכתוב יישום Qt עבור Raspberry Pi 4 שניתן להשתמש בו כדי לעבור בין נקודות גישה WLAN שונות ולאחסן את האישורים המשויכים.
השתמשתי בתמונת Raspbian-buster-lite ובמיצב Qt כמתואר ב-Qt על Raspberry Pi 4 כנקודת התחלה.
בנוסף, התקנתי את מנהל הרשת, אשר ניתן להשתמש בו על ידי הפקודה פגז (nmcli ...) צור, קבע תצורה ונהל חיבורי רשת.
מידע על כך ניתן למצוא תחת https://wiki.debian.org/de/NetworkManager או https://developer.gnome.org/NetworkManager/stable/nmcli.html.
מנהל הרשת מציע פקודה שניתן להשתמש בה כדי להתחיל תהליך ניטור, אשר לאחר מכן מעיר על שינויים בממשקים השונים (wlan0 או eth0) (למשל לא זמין, מנותק, מתחבר, מחובר, ...).
רציתי להשתמש בניטור זה כדי להציג את הסטטוסים השונים של מיקומי הרשת בממשק המשתמש הגרפי. התגלו 2 בעיות:

  • אם מספר פקודות NMCLI הונפקו ברצף מהיר, אז המשוב על הסטטוסים השונים הגיע עם עיכוב זמן ולא ניתן היה להציג אותו חי בממשק המשתמש הגרפי.
  • המשוב של פקודות NMCLI נשלח בחריצים שונים ולכן יכול להיות מתואם בצורה גרועה.

פונקציית ניטור

קודם כל, אנחנו צריכים את פונקציית הניטור (monitorDevices) ואת פונקציית החריץ הציבורי, אשר מיירט ומעריך את פלט הניטור ולאחר מכן שולח את הודעות המצב לממשק המשתמש הגרפי, למשל.
בפונקציה "monitorDevices", שמתחילה באופן אוטומטי כאשר היישום מופעל, הפקודה nmcli מופעלת עם sudo: sudo nmcli monitor
המשפט "setProcessChannelMode(QProcess::MergedChannels)" מציין כי "פלט סטנדרטי" ו"שגיאה סטנדרטית" מוצגים יחד בערוץ ולכן ניתן להעריך אותם באמצעות פונקציה.
השורה "connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" משמשת בכל פעם שמוצגת הודעה (readyReadStandardOutput), היא נשלחת לחריץ "processOutput".

void CmdLauncher::monitorDevices() {
QStringList device_monitoring_on = {"nmcli", "monitor"};
device_monitoring_process = new QProcess(this);
device_monitoring_process->setProcessChannelMode(QProcess::MergedChannels);
device_monitoring_process->start("sudo", device_monitoring_on);
connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
}

</:code1:>

פונקציית הערכה

הערכת ההודעות מתבצעת לאחר מכן בפונקציה "processOutput". תהליך השולח של QProcess מיירט את כל ההודעות של כל פקודות nmcli - לא רק את אלה של פקודת הניטור.

void CmdLauncher::processOutput() {
QProcess* senderProcess = qobject_cast<QProcess*>(sender());
senderProcess->setReadChannel(QProcess::StandardOutput);
QString message = QString::fromLocal8Bit(senderProcess->readAllStandardOutput());

qDebug() << "CmdLauncher::processOutput message: " << message << endl;
if (message.contains("Error:")) {
    message.remove(QString("\n"));
    error_messages = message;
    emit getErrorMessagesChanged();
    if (message.contains(QString("Error: unknown connection"))) {
        secrets_required = true;
        emit getSecretsRequiredChanged();
    }
}
// wifi
if (message.contains("wlan0: connected") || message.contains("wlan0:connected")) {
    wifi_device_state = "Wifi-Connected";
    emit getWifiDeviceStateChanged();
    error_messages = "";
    emit getErrorMessagesChanged();
    rescanWifi();
    testInternetConnection();
}

}

</:code2:>

התחלת תהליך nmcli נוסף

אם כעת אתה מפעיל פקודת nmcli נוספת עם הפונקציה למטה, הפלט מיורט על ידי פונקציית הניטור לעיל ולאחר מכן ניתן להעריך ולעבד אותו עוד יותר ב- "outputProcess".
פונקציה זו עוברת לחיבור רשת קיים ומפעילה אותו. חשוב לא לכלול "set_wifi_process->waitForReadyRead()" או "set_wifi_process->waitForFinished()", מכיוון שאז הפלט של כל ההודעות ייחסם עד לסיום תהליך זה.

void CmdLauncher::setWifi(QString ssid) {
    error_messages = "";
    emit getErrorMessagesChanged();

    QString uuid = "";
    for (int i = 0 ; i  networkConnections.length() ; i++) {
        QStringList connections = networkConnections[i].split(":");
        if (connections[1] == ssid)
        {
            uuid = connections[2];
        }
    }

    QStringList args_wifi_exist = {"nmcli", "connection", "up", uuid};
    set_wifi_process = new QProcess(this);
    set_wifi_process->setProcessChannelMode(QProcess::MergedChannels);
    set_wifi_process->start("sudo", args_wifi_exist);
    connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
}

השורה "connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput())))" מעבירה את הודעות הפלט של תהליך זה בחזרה אל "processOutput" וניתן להעריך אותה שם שוב במיקום מרכזי. </:code3:>

Walter Prechtl

Walter Prechtl

עודכן ב-: 12. March 2024
זמן קריאה: 4 דקות