كان الهدف هو كتابة تطبيق Qt ل Raspberry Pi 4 والذي يمكن استخدامه للتبديل بين نقاط وصول WLAN المختلفة وتخزين بيانات الاعتماد المرتبطة بها.
لقد استخدمت صورة raspbian-buster-lite وتثبيت Qt كما هو موضح في Qt على Raspberry Pi 4 كنقطة انطلاق.
بالإضافة إلى ذلك ، قمت بتثبيت NetworkManager ، والذي يمكن استخدامه بواسطة أمر shell (nmcli ...) إنشاء اتصالات الشبكة وتكوينها وإدارتها.
يمكن العثور على معلومات حول هذا تحت https://wiki.debian.org/de/NetworkManager أو https://developer.gnome.org/NetworkManager/stable/nmcli.html.
يقدم NetworkManager أمرا يمكن استخدامه لبدء عملية المراقبة ، والتي تعلق بعد ذلك على التغييرات التي تطرأ على الواجهات المختلفة (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 senderProcess جميع رسائل جميع أوامر 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:>