CoAPマルチキャストのクイック検出
Qt Quick ユーザーインターフェースを使用した、CoAPクライアントによるマルチキャストリソースの検出。

「Quick CoAP Multicast Discovery」サンプルでは、QCoapClient をQMLタイプとして登録し、Qt Quick アプリケーション内でCoAPマルチキャストリソースの検出に利用する方法について解説します。
注: Qt CoAP の 現在のバージョンでは、QML APIは提供されていません。ただし、この例に示すように、モジュールのC++クラスをQMLから利用できるようにすることは可能です。
例の実行
以下の手順で例を実行できます。
- Qt Creator
Welcome モードを開き、Examples からこの例を選択します。詳細については、Qt Creator の「チュートリアル:ビルドと実行」を参照してください。
- Qt Extension for Visual Studio Code
「Command Palette 」から「Qt: Open Qt examples 」コマンドを実行し、リストからこの例を選択します。詳細については、Qt Extension for Visual Studio Code の「チュートリアル: ビルドと実行」を参照してください。
CoAP サーバーの設定
サンプルアプリケーションを実行するには、まず、マルチキャストリソースディスカバリをサポートするCoAPサーバーを少なくとも1台セットアップして起動する必要があります。以下のオプションがあります。
- libcoap、Californium、またはマルチキャストおよびリソースディスカバリー機能をサポートするその他の CoAP サーバー実装を使用して、CoAP サーバーを手動でビルドおよび実行します。
- Docker Hub で入手可能な既製の Docker イメージを使用します。このイメージは、Californiumのマルチキャストサーバーのサンプルに基づいて CoAP サーバーをビルドおよび起動します。
Docker ベースのテストサーバーの使用
次のコマンドを実行すると、Docker Hub から CoAP サーバー用の Docker コンテナを取得して起動します:
docker run --name coap-multicast-server -d --rm --net=host tqtc/coap-multicast-test-server:californium-2.0.0注: 上記のコマンドに異なる--name を指定することで、(同じホスト上またはネットワーク内の他のホスト上で)複数のマルチキャストCoAPサーバーを実行できます 。
使用後にDockerコンテナを終了するには、まずdocker ps コマンドを実行してコンテナのIDを取得します。出力は次のようになります:
$ docker ps
CONTAINER ID IMAGE
8b991fae7789 tqtc/coap-multicast-test-server:californium-2.0.0その後、このIDを使用してコンテナを停止します:
docker stop <container_id>C++ クラスを QML に公開する
この例では、QCoapResource およびQCoapClient クラス、ならびにQtCoap 名前空間を QML に公開する必要があります。これを実現するには、カスタムラッパークラスを作成し、専用の登録マクロを使用します。
`QCoapResource` をラップする `QmlCoapResource ` クラスを作成します。`Q_PROPERTY ` マクロを使用して、QML からいくつかのプロパティにアクセスできるようにします。このクラスは QML から直接インスタンス化できる必要がないため、`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(); }
};その後、QCoapClient クラスを基底クラスとしてQmlCoapMulticastClient クラスを作成します。Q_PROPERTY マクロを使用してカスタムプロパティを公開し、さらにいくつかのQ_INVOKABLE メソッドを作成します。プロパティとinvokableメソッドの両方にQMLからアクセスできます。QmlCoapResource とは異なり、このクラスはQMLからインスタンス化できるようにする必要があるため、QML_NAMED_ELEMENT マクロを使用してQMLにクラスを登録します。
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;
};最後に、QtCoap 名前空間を登録して、そこに定義されている列挙型を使用できるようにします:
namespace QCoapForeignNamespace
{
Q_NAMESPACE
QML_FOREIGN_NAMESPACE(QtCoap)
QML_NAMED_ELEMENT(QtCoap)
}ビルドファイルの調整
QMLからカスタム型を利用できるようにするには、ビルドシステムファイルを適宜更新します。
CMake ビルド
CMake ベースのビルドの場合、CMakeLists.txt に以下を追加します:
qt_add_qml_module(quickmulticastclient
URI CoapClientModule
VERSION 1.0
SOURCES
qmlcoapmulticastclient.cpp qmlcoapmulticastclient.h
QML_FILES
Main.qml
)qmake ビルド
qmakeによるビルドの場合は、quickmulticastclient.pro ファイルを次のように変更してください:
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新しいQML型の使用
これで、C++ クラスが QML に対して適切に公開されたため、新しい型を使用できるようになります:
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)
}
}QmlCoapMulticastClient::finished() シグナルは、onFinished シグナルハンドラをトリガーし、UIにリクエストのステータスを表示します。なお、この例ではQCoapClient のシグナルを直接使用していません。これは、error()およびfinished()の両方のシグナルがQCoapReply をパラメータとして受け取る(これはQMLには公開されていない)のに対し、この例ではエラーコードのみが必要であるためです。
QmlCoapMulticastClient のコンストラクタは、QCoapClient のシグナルをQmlCoapMulticastClient::finished() シグナルに転送します:
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));
});
}Discover のボタンが押されると、選択されたマルチキャストグループに基づいて、discover() のオーバーロードされたメソッドのいずれかが呼び出されます:
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);
}
}
}このオーバーロードは、カスタムマルチキャストグループまたはホストアドレスが選択されたときに呼び出されます:
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.");
}
}また、UIで提案されたマルチキャストグループのいずれかが選択された場合、このオーバーロードが呼び出されます:
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.");
}
}QCoapResourceDiscoveryReply::discovered() シグナルは、QML 型ではない `QCoapResource` のリストを送信します。QML でリソースを利用できるようにするには、リスト内の各リソースを `QmlCoapMulticastClient::discovered() ` シグナルに転送します。このシグナルは代わりに `QmlCoapResource ` を受け取ります:
void QmlCoapMulticastClient::onDiscovered(QCoapResourceDiscoveryReply *reply,
const QList<QCoapResource> &resources)
{
Q_UNUSED(reply)
for (const auto &resource : resources)
emit discovered(resource);
}検出されたリソースは、UI上のリストビューのresourceModel に追加されます:
function addResource(resource) {
resourceModel.insert(0, {"host" : resource.host,
"path" : resource.path,
"title" : resource.title})
}検出が進行中の場合、Stop Discovery ボタンを押すと検出を停止できます。内部的には、現在のリクエストを中止することで処理されます:
void QmlCoapMulticastClient::stopDiscovery()
{
if (m_reply)
m_reply->abortRequest();
}ファイル:
© 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.