Schnelle CoAP-Multicast-Ermittlung
Verwendung des CoAP-Clients für eine Multicast-Ressourcenermittlung mit einer Qt Quick Benutzeroberfläche.
Das Beispiel für die schnelle CoAP-Multicast-Ermittlung zeigt, wie QCoapClient als QML-Typ registriert und in einer Qt Quick -Anwendung für die CoAP-Multicast-Ressourcenermittlung verwendet werden kann.
Hinweis: Qt CoAP bietet in seiner aktuellen Version keine QML-API. Sie können jedoch die C++-Klassen des Moduls für QML verfügbar machen, wie in diesem Beispiel gezeigt.
Ausführen des Beispiels
Zum Ausführen des Beispiels von Qt Creatorzu starten, öffnen Sie den Modus Welcome und wählen Sie das Beispiel aus Examples. Weitere Informationen finden Sie unter Erstellen und Ausführen eines Beispiels.
Einrichten eines CoAP-Servers
Um die Beispielanwendung auszuführen, müssen Sie zunächst mindestens einen CoAP-Server einrichten und starten, der die Multicast-Ressourcenerkennung unterstützt. Sie haben die folgenden Möglichkeiten:
- Manuelles Erstellen und Ausführen von CoAP-Servern mit libcoap, Californium oder einer anderen CoAP-Server-Implementierung, die Multicast- und Ressourcenerkennungsfunktionen unterstützt.
- Verwenden Sie das fertige Docker-Image, das auf Docker Hub verfügbar ist und CoAP-Server auf der Grundlage des Multicast-Serverbeispiels von Californium erstellt und startet.
Verwendung des Docker-basierten Test-Servers
Der folgende Befehl zieht den Docker-Container für den CoAP-Server aus dem Docker Hub und startet ihn:
docker run --name coap-multicast-server -d --rm --net=host tqtc/coap-multicast-test-server:californium-2.0.0
Hinweis: Sie können mehr als einen Multicast-CoAP-Server betreiben (auf demselben Host oder anderen Hosts im Netzwerk), indem Sie dem obigen Befehl ein anderes --name
übergeben.
Um den Docker-Container nach der Verwendung zu beenden, erhalten Sie zunächst die ID des Containers, indem Sie den Befehl docker ps
ausführen. Die Ausgabe sieht dann wie folgt aus:
$ docker ps CONTAINER ID IMAGE 8b991fae7789 tqtc/coap-multicast-test-server:californium-2.0.0
Danach verwenden Sie diese ID, um den Container zu beenden:
docker stop <container_id>
C++-Klassen für QML freilegen
In diesem Beispiel müssen Sie die Klassen QCoapResource und QCoapClient sowie den Namespace QtCoap für QML freigeben. Um dies zu erreichen, erstellen Sie benutzerdefinierte Wrapper-Klassen und verwenden die speziellen Registrierungsmakros.
Erstellen Sie die Klasse QmlCoapResource
als Wrapper um QCoapResource. Verwenden Sie das Makro Q_PROPERTY, um mehrere Eigenschaften von QML aus zugänglich zu machen. Die Klasse muss nicht direkt von QML aus instanzierbar sein, verwenden Sie also das QML_ANONYMOUS Makro, um sie zu registrieren.
class QmlCoapResource : public QCoapResource { Q_GADGET Q_PROPERTY(QString title READ title) Q_PROPERTY(QString host READ hostStr) Q_PROPERTY(QString path READ path) QML_ANONYMOUS public: QmlCoapResource() : QCoapResource() {} QmlCoapResource(const QCoapResource &resource) : QCoapResource(resource) {} QString hostStr() const { return host().toString(); } };
Danach erstellen Sie die Klasse QmlCoapMulticastClient
mit der Klasse QCoapClient als Basisklasse. Verwenden Sie das Makro Q_PROPERTY, um eine benutzerdefinierte Eigenschaft freizugeben, und erstellen Sie außerdem mehrere Methoden Q_INVOKABLE. Sowohl auf die Eigenschaft als auch auf die aufrufbaren Methoden kann von QML aus zugegriffen werden. Im Gegensatz zu QmlCoapResource
möchten Sie diese Klasse von QML aus erstellen können, daher verwenden Sie das Makro QML_NAMED_ELEMENT, um die Klasse in QML zu registrieren.
class QmlCoapMulticastClient : public QCoapClient { Q_OBJECT Q_PROPERTY(bool isDiscovering READ isDiscovering NOTIFY isDiscoveringChanged) QML_NAMED_ELEMENT(CoapMulticastClient) public: QmlCoapMulticastClient(QObject *parent = nullptr); Q_INVOKABLE void discover(const QString &host, int port, const QString &discoveryPath); Q_INVOKABLE void discover(QtCoap::MulticastGroup group, int port, const QString &discoveryPath); Q_INVOKABLE void stopDiscovery(); bool isDiscovering() const; Q_SIGNALS: void discovered(const QmlCoapResource &resource); void finished(int error); // The bool parameter is not provided, because the signal is only used by // the QML property system, and it does not use the passed value anyway. void isDiscoveringChanged(); public slots: void onDiscovered(QCoapResourceDiscoveryReply *reply, const QList<QCoapResource> &resources); private: QCoapResourceDiscoveryReply *m_reply = nullptr; };
Schließlich registrieren Sie den Namespace QtCoap, damit Sie die dort bereitgestellten Enums verwenden können:
namespace QCoapForeignNamespace { Q_NAMESPACE QML_FOREIGN_NAMESPACE(QtCoap) QML_NAMED_ELEMENT(QtCoap) }
Anpassen der Build-Dateien
Um die benutzerdefinierten Typen in QML verfügbar zu machen, aktualisieren Sie die Build-Systemdateien entsprechend.
CMake-Build
Für einen CMake-basierten Build, fügen Sie folgendes zur CMakeLists.txt
hinzu:
qt_add_qml_module(quickmulticastclient URI CoapClientModule VERSION 1.0 SOURCES qmlcoapmulticastclient.cpp qmlcoapmulticastclient.h QML_FILES Main.qml )
qmake Build
Für einen qmake-Build ändern Sie die Datei quickmulticastclient.pro
auf folgende Weise:
CONFIG += qmltypes QML_IMPORT_NAME = CoapClientModule QML_IMPORT_MAJOR_VERSION = 1 ... qml_resources.files = \ qmldir \ Main.qml qml_resources.prefix = /qt/qml/CoapClientModule RESOURCES += qml_resources
Neue QML-Typen verwenden
Nun, da die C++-Klassen ordnungsgemäß in QML exponiert sind, können Sie die neuen Typen verwenden:
CoapMulticastClient { id: client onDiscovered: (resource) => { root.addResource(resource) } onFinished: (error) => { statusLabel.text = (error === QtCoap.Error.Ok) ? qsTr("Finished resource discovery.") : qsTr("Resource discovery failed with error code: %1").arg(error) } }
Das Signal QmlCoapMulticastClient::finished()
löst den Signalhandler onFinished
aus, um den Status der Anfrage in der Benutzeroberfläche anzuzeigen. Beachten Sie, dass das Beispiel die Signale von QCoapClient nicht direkt verwendet, da die Signale error() und finished() ein QCoapReply als Parameter benötigen (das nicht in QML verfügbar ist), und das Beispiel nur den Fehlercode benötigt.
Der Konstruktor von QmlCoapMulticastClient
leitet die Signale von QCoapClient an das Signal QmlCoapMulticastClient::finished()
weiter:
QmlCoapMulticastClient::QmlCoapMulticastClient(QObject *parent) : QCoapClient(QtCoap::SecurityMode::NoSecurity, parent) { connect(this, &QCoapClient::finished, this, [this](QCoapReply *reply) { if (reply) { emit finished(static_cast<int>(reply->errorReceived())); reply->deleteLater(); if (m_reply == reply) { m_reply = nullptr; emit isDiscoveringChanged(); } } else { qCWarning(lcCoapClient, "Something went wrong, received a null reply"); } }); connect(this, &QCoapClient::error, this, [this](QCoapReply *, QtCoap::Error err) { emit finished(static_cast<int>(err)); }); }
Wenn die Schaltfläche Discover gedrückt wird, wird eine der überladenen Methoden discover()
aufgerufen, basierend auf der ausgewählten Multicast-Gruppe:
Button { id: discoverButton text: client.isDiscovering ? qsTr("Stop Discovery") : qsTr("Discover") Layout.preferredWidth: 100 onClicked: { if (client.isDiscovering) { client.stopDiscovery() } else { var currentGroup = groupComboBox.model.get(groupComboBox.currentIndex).value; var path = ""; if (currentGroup !== - 1) { client.discover(currentGroup, parseInt(portField.text), discoveryPathField.text); path = groupComboBox.currentText; } else { client.discover(customGroupField.text, parseInt(portField.text), discoveryPathField.text); path = customGroupField.text + discoveryPathField.text; } statusLabel.text = qsTr("Discovering resources at %1...").arg(path); } } }
Diese Überladung wird aufgerufen, wenn eine benutzerdefinierte Multicast-Gruppe oder eine Host-Adresse ausgewählt wird:
void QmlCoapMulticastClient::discover(const QString &host, int port, const QString &discoveryPath) { QUrl url; url.setHost(host); url.setPort(port); m_reply = QCoapClient::discover(url, discoveryPath); if (m_reply) { connect(m_reply, &QCoapResourceDiscoveryReply::discovered, this, &QmlCoapMulticastClient::onDiscovered); emit isDiscoveringChanged(); } else { qCWarning(lcCoapClient, "Discovery request failed."); } }
Und diese Überladung wird aufgerufen, wenn eine der vorgeschlagenen Multicast-Gruppen in der Benutzeroberfläche ausgewählt wird:
void QmlCoapMulticastClient::discover(QtCoap::MulticastGroup group, int port, const QString &discoveryPath) { m_reply = QCoapClient::discover(group, port, discoveryPath); if (m_reply) { connect(m_reply, &QCoapResourceDiscoveryReply::discovered, this, &QmlCoapMulticastClient::onDiscovered); emit isDiscoveringChanged(); } else { qCWarning(lcCoapClient, "Discovery request failed."); } }
Das Signal QCoapResourceDiscoveryReply::discovered() liefert eine Liste von QCoapResources, die kein QML-Typ ist. Um die Ressourcen in QML verfügbar zu machen, leiten Sie jede Ressource in der Liste an das Signal QmlCoapMulticastClient::discovered()
weiter, das stattdessen ein QmlCoapResource
entgegennimmt:
void QmlCoapMulticastClient::onDiscovered(QCoapResourceDiscoveryReply *reply, const QList<QCoapResource> &resources) { Q_UNUSED(reply) for (const auto &resource : resources) emit discovered(resource); }
Die gefundenen Ressourcen werden der resourceModel
der Listenansicht in der Benutzeroberfläche hinzugefügt:
function addResource(resource) { resourceModel.insert(0, {"host" : resource.host, "path" : resource.path, "title" : resource.title}) }
Während die Erkennung läuft, können Sie die Schaltfläche Stop Discovery drücken, um die Erkennung zu beenden. Intern geschieht dies durch den Abbruch der aktuellen Anfrage:
void QmlCoapMulticastClient::stopDiscovery() { if (m_reply) m_reply->abortRequest(); }
Dateien:
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.