เป้าหมายคือการเขียนแอปพลิเคชัน 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)" ระบุว่า "เอาต์พุตมาตรฐาน" และ "ข้อผิดพลาดมาตรฐาน" จะแสดงร่วมกันในแชนเนลและสามารถประเมินได้ด้วยฟังก์ชัน
บรรทัด "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:>