هدف این بود که یک برنامه Qt برای Raspberry Pi 4 بنویسیم که می تواند برای تغییر بین نقاط دسترسی مختلف WLAN و ذخیره اعتبار مرتبط استفاده شود.
من از یک تصویر raspbian-buster-lite و نصب Qt همانطور که در Qt در Raspberry Pi 4 به عنوان نقطه شروع توصیف شده است استفاده کردم.
علاوه بر این، من NetworkManager را نصب کرده ام که می تواند توسط فرمان پوسته (nmcli ...) ایجاد، پیکربندی و مدیریت اتصالات شبکه.
اطلاعات در این مورد را می توان در https://wiki.debian.org/de/NetworkManager یا https://developer.gnome.org/NetworkManager/stable/nmcli.html یافت.
NetworkManager فرمانی را ارائه می دهد که می تواند برای شروع یک فرایند نظارت مورد استفاده قرار گیرد، که سپس در مورد تغییرات در رابط های مختلف (wlan0 یا eth0) (به عنوان مثال در دسترس نیست، قطع شده، اتصال، متصل، ...)
من می خواستم از این نظارت برای نمایش وضعیت های مختلف مکان های شبکه در GUI استفاده کنم. 2 مشکل ظاهر شد:
- اگر چندین فرمان nmcli به سرعت صادر شود، بازخورد در مورد وضعیت های مختلف با تاخیر زمانی وارد می شود و نمی تواند به صورت زنده در GUI نمایش داده شود.
- بازخورد دستورات nmcli در اسلات های مختلف ارسال شد و بنابراین می تواند ضعیف هماهنگ شود.
عملکرد مانیتورینگ
اول از همه، ما نیاز به تابع نظارت (monitorDevices) و تابع اسلات عمومی داریم که خروجی نظارت را رهگیری و ارزیابی می کند و سپس پیام های وضعیت را به GUI ارسال می کند.
در تابع "monitorDevices"، که به طور خودکار با شروع برنامه شروع می شود، فرمان nmcli با sudo اغاز می شود: sudo nmcli monitor
عبارت "setProcessChannelMode(QProcess::MergedChannels)" بیان می کند که "Standard Output" و "Standard Error" با هم در یک کانال نمایش داده می شوند و بنابراین می توانند با یک تابع ارزیابی شوند.
خط "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:>