빠른 CoAP 멀티캐스트 검색
Qt Quick 사용자 인터페이스로 멀티캐스트 리소스 검색을 위해 CoAP 클라이언트 사용하기.
빠른 CoAP 멀티캐스트 검색 예제에서는 QCoapClient 을 QML 유형으로 등록하고 Qt Quick 애플리케이션에서 CoAP 멀티캐스트 리소스 검색을 위해 사용하는 방법을 보여줍니다.
참고: Qt CoAP 는 현재 버전에서 QML API를 제공하지 않습니다. 그러나 이 예제와 같이 모듈의 C++ 클래스를 QML에서 사용할 수 있도록 설정할 수 있습니다.
예제 실행하기
에서 예제를 실행하려면 Qt Creator에서 Welcome 모드를 열고 Examples 에서 예제를 선택합니다. 자세한 내용은 예제 빌드 및 실행하기를 참조하세요.
CoAP 서버 설정하기
예제 애플리케이션을 실행하려면 먼저 멀티캐스트 리소스 검색을 지원하는 CoAP 서버를 하나 이상 설정하고 시작해야 합니다. 다음과 같은 옵션이 있습니다:
- 멀티캐스트 및 리소스 검색 기능을 지원하는 libcoap, Californium 또는 기타 CoAP 서버 구현을 사용하여 수동으로 CoAP 서버를 빌드하고 실행합니다.
- 캘리포니아의 멀티캐스트 서버 예제를 기반으로 CoAP 서버를 빌드하고 시작하는 Docker Hub에서 제공되는 준비된 Docker 이미지를 사용합니다.
Docker 기반 테스트 서버 사용
다음 명령은 도커 허브에서 CoAP 서버용 도커 컨테이너를 가져와서 시작합니다:
docker run --name coap-multicast-server -d --rm --net=host tqtc/coap-multicast-test-server:californium-2.0.0
참고: 위의 명령에 다른 --name
을 전달하여 동일한 호스트 또는 네트워크의 다른 호스트에서 둘 이상의 멀티캐스트 CoAP 서버를 실행할 수 있습니다.
사용 후 도커 컨테이너를 종료하려면 먼저 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에 노출해야 합니다. 이를 위해 사용자 지정 래퍼 클래스를 만들고 특수 등록 매크로를 사용합니다.
QmlCoapResource
클래스를 QCoapResource 을 감싸는 래퍼로 만듭니다. 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 메서드도 만듭니다. 프로퍼티와 호출 가능한 메서드 모두 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에 표시합니다. error () 및 finished() 신호는 모두 (QML에 노출되지 않는) QCoapReply 을 매개변수로 사용하며 이 예제에서는 오류 코드만 필요하므로 QCoapClient 의 신호를 직접 사용하지 않습니다.
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(); }
Files:
© 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.