Schnelle CoAP-Multicast-Erkennung
Verwendung des CoAP-Clients zur Multicast-Ressourcenerkennung mit einer Benutzeroberfläche nach dem „ Qt Quick “-Prinzip.

Das Beispiel „Schnelle CoAP-Multicast-Erkennung“ veranschaulicht, wie man „ QCoapClient “ als QML-Typ registriert und in einer „ Qt Quick “-Anwendung zur CoAP-Multicast-Ressourcenerkennung einsetzt.
Hinweis: „ Qt CoAP “ bietet in der 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
Sie können das Beispiel wie folgt ausführen:
- Qt Creator
Öffnen Sie den „ Welcome “-Modus und wählen Sie das Beispiel unter „ Examples “ aus. Weitere Informationen finden Sie unter Qt Creator: Tutorial: Erstellen und Ausführen.
- Qt Extension for Visual Studio Code
Führen Sie den Befehl „ Qt: Open Qt examples “ aus dem Verzeichnis „ Command Palette “ aus und wählen Sie das Beispiel aus der Liste aus. Weitere Informationen finden Sie unter Qt Extension for Visual Studio Code: Tutorial: Erstellen und Ausführen.
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. Ihnen stehen folgende Optionen zur Verfügung:
- Erstellen und starten Sie CoAP-Server manuell mithilfe von libcoap, Californium oder einer anderen CoAP-Server-Implementierung, die Multicast- und Ressourcenerkennungsfunktionen unterstützt.
- Verwenden Sie das auf Docker Hub verfügbare fertige Docker-Image, das einen CoAP-Server auf Basis des Multicast-Server-Beispiels von Californium erstellt und startet.
Verwendung des Docker-basierten Test-Servers
Der folgende Befehl ruft den Docker-Container für den CoAP-Server von Docker Hub ab und startet ihn:
docker run --name coap-multicast-server -d --rm --net=host tqtc/coap-multicast-test-server:californium-2.0.0Hinweis: Sie können mehrere Multicast-CoAP-Server (auf demselben Host oder auf anderen Hosts im Netzwerk) ausführen, indem Sie dem obigen Befehl eine andere ` --name ` übergeben.
Um den Docker-Container nach der Nutzung zu beenden, ermitteln Sie zunächst die ID des Containers, indem Sie den Befehl ` docker ps ` ausführen. Die Ausgabe sieht wie folgt aus:
$ docker ps
CONTAINER ID IMAGE
8b991fae7789 tqtc/coap-multicast-test-server:californium-2.0.0Verwenden Sie anschließend diese ID, um den Container zu beenden:
docker stop <container_id>C++-Klassen für QML verfügbar machen
In diesem Beispiel müssen Sie die Klassen „ QCoapResource “ und „ QCoapClient “ sowie den Namespace „ QtCoap “ für QML verfügbar machen. Erstellen Sie dazu benutzerdefinierte Wrapper-Klassen und verwenden Sie die speziellen Registrierungsmakros.
Erstellen Sie die Klasse „ QmlCoapResource “ als Wrapper für „ QCoapResource “. Verwenden Sie das Makro „ Q_PROPERTY “, um mehrere Eigenschaften für QML zugänglich zu machen. Da die Klasse nicht direkt aus QML instanziierbar sein muss, registrieren Sie sie mit dem Makro „ QML_ANONYMOUS “.
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(); }
};Erstellen Sie anschließend 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 mit dem Makro „ Q_INVOKABLE “. Sowohl auf die Eigenschaft als auch auf die aufrufbaren Methoden kann von QML aus zugegriffen werden. Im Gegensatz zu „ QmlCoapResource “ soll diese Klasse von QML aus instanziierbar sein; verwenden Sie daher 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;
};Registrieren Sie abschließend den Namespace „ QtCoap “, damit Sie die dort bereitgestellten Enums verwenden können:
namespace QCoapForeignNamespace
{
Q_NAMESPACE
QML_FOREIGN_NAMESPACE(QtCoap)
QML_NAMED_ELEMENT(QtCoap)
}Anpassung der Build-Dateien
Um die benutzerdefinierten Typen in QML verfügbar zu machen, aktualisieren Sie die Dateien des Build-Systems entsprechend.
CMake-Build
Fügen Sie bei einem CMake-basierten Build Folgendes in die Datei „ CMakeLists.txt “ ein:
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 “ wie folgt:
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_resourcesVerwendung neuer QML-Typen
Sobald die C++-Klassen ordnungsgemäß für QML verfügbar 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 Signal-Handler „ 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 sowohl das Signal „ error()“ als auch das Signal „ finished()“ ein „ QCoapReply “ als Parameter benötigen (das nicht für QML verfügbar ist) und das Beispiel lediglich 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 je nach ausgewählter Multicast-Gruppe eine der überladenen Methoden von ` discover() ` aufgerufen:
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 einen „ QmlCoapResource “ erwartet:
void QmlCoapMulticastClient::onDiscovered(QCoapResourceDiscoveryReply *reply,
const QList<QCoapResource> &resources)
{
Q_UNUSED(reply)
for (const auto &resource : resources)
emit discovered(resource);
}Die erkannten Ressourcen werden dem „ resourceModel “ der Listenansicht in der Benutzeroberfläche hinzugefügt:
function addResource(resource) {
resourceModel.insert(0, {"host" : resource.host,
"path" : resource.path,
"title" : resource.title})
}Drücken Sie während der Erkennung auf die Schaltfläche „ Stop Discovery “, um die Erkennung zu beenden. Intern erfolgt dies durch Abbruch der aktuellen Anfrage:
void QmlCoapMulticastClient::stopDiscovery()
{
if (m_reply)
m_reply->abortRequest();
}Dateien:
© 2026 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.