콘텐츠로 이동
무료 평가 시작

pdcomm::opcua::qt_client_worker

클래스

네이티브 OPC UA 클라이언트를 소유하는 일회용 QThread입니다.

class qt_client_worker final : public QThread

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

run()은 연결하고, 세션(session)을 (익명 또는 사용자 이름으로) 활성화하고, ready()를 내보낸 뒤, 제출된 요청을 순서대로 보내고, 폴링하며, 응답마다 completed()를 내보냅니다. request_stop() 또는 치명적 오류 후 끝나며, 항상 마지막에 stopped()를 내보냅니다. 워커는 한 번만 실행됩니다. 다시 시작하면 "restart-rejected"를 보고합니다.

애플리케이션이 지켜야 할 규칙:

  • wait()가 반환될 때까지 객체를 소유합니다. 객체 자신의 스레드에서 객체를 소멸시키지 않습니다.
  • 모든 시그널(signal)은 수신자 컨텍스트 객체와 Qt::QueuedConnection으로 연결합니다. 그러면 핸들러가 수신자의 스레드에서 실행되고, 수신자가 소멸하면 Qt가 연결을 끊습니다. QPointer를 확인한 뒤 다른 스레드에서 원시 수신자 포인터를 호출하지 않습니다.
  • submit()과 request_stop()은 스레드 안전(thread-safe)합니다. 그 밖의 모든 멤버 함수는 소유자 스레드에 속합니다.

실패는 네이티브 호출의 C ABI 상태를 따릅니다.

  • 요청 실패는 해당 요청만 끝내며, 워커는 다른 요청을 계속 처리합니다. client::begin()이 #PDCOMM_OPCUA_INVALID_INPUT이나 #PDCOMM_OPCUA_LIMIT으로 거부하는 경우(phase "begin"), 또는 서버가 응답을 중단했거나 응답이 잘못되어 client::take()가 #PDCOMM_OPCUA_RUNTIME_ERROR로 완료하는 경우(phase "response")입니다. 이런 요청은 completed로 집계됩니다.
  • 핸들 레지스트리가 가득 찬 것은 실패가 아닙니다. client::take()가 #PDCOMM_OPCUA_LIMIT을 보고하고 네이티브 클라이언트가 응답을 보관합니다. 그동안 다른 모든 클라이언트 호출은 #PDCOMM_OPCUA_BUSY를 반환하므로 워커는 그 take만 재시도하고, 애플리케이션이 응답을 해제하면 응답을 전달합니다. 레지스트리가 timeout_ms 동안 계속 가득 차 있으면 워커는 #PDCOMM_OPCUA_LIMIT으로 끝납니다.
  • 그 밖의 모든 네이티브 오류는 워커를 끝냅니다. 연결, 활성화, poll(연결 끊김, 요청 타임아웃, 보안 실패), close, 그리고 잘못된 응답이 연결을 닫은 뒤의 #PDCOMM_OPCUA_CLOSED 같은 그 밖의 begin 또는 take 상태가 해당합니다. 워커는 "worker" 실패를 내보내고, 남은 요청을 phase "abort"로 실패시키고, 이유 "native-error"로 멈춥니다.

examples/opcua/qt/opcua_qt_client.cpp에서 발췌:

qt_client_configuration configuration;
configuration.endpoint = arguments[1].toUtf8();
configuration.anonymous = true;
// ... load certificate_der, private_key_pem and trusted_server_der
QObject receiver;  // Stable receiver context for every queued connection.
auto worker = std::make_unique<qt_client_worker>(configuration);
// The worker copied the configuration; wipe the caller copy of the key.
configuration.private_key_pem.fill('\0');
configuration.private_key_pem.clear();
QObject::connect(worker.get(), &qt_client_worker::ready, &receiver, [&](quintptr) {
  uint8_t request[256];
  const auto size = ua_encode_read(request, sizeof(request), 2, node);
  const auto status = worker->submit(QByteArray(reinterpret_cast<const char*>(request),
                                                static_cast<qsizetype>(size)), 1);
  if (status != PDCOMM_OPCUA_OK) {
    std::fprintf(stderr, "Error: submit rejected (SDK status %d)\n", static_cast<int>(status));
    worker->request_stop(qt_client_stop::abort);
  }
}, Qt::QueuedConnection);
QObject::connect(worker.get(), &qt_client_worker::completed, &receiver,
                 [&](qt_client_response_ptr response) {
  const auto body = response->value->copy();
  // ... decode the ReadResponse
  worker->request_stop(qt_client_stop::drain);
}, Qt::QueuedConnection);
QObject::connect(worker.get(), &qt_client_worker::failed, &receiver, [&](qt_client_failure failure) {
  std::fprintf(stderr, "Error: %s failed (SDK status %d): %s\n", failure.phase.toUtf8().constData(),
               static_cast<int>(failure.status), failure.text.toUtf8().constData());
  result = 3;
  worker->request_stop(qt_client_stop::abort);
}, Qt::QueuedConnection);
QObject::connect(worker.get(), &qt_client_worker::stopped, &receiver, [&](qt_client_terminal terminal) {
  std::printf("Worker stopped orderly=%s\n", terminal.orderly ? "true" : "false");
  std::fflush(stdout);
  application.quit();
}, Qt::QueuedConnection);
worker->start();
application.exec();
worker->wait();
worker.reset();

멤버

completed

이벤트

검증된 응답이 도착했습니다. 요청은 끝났습니다.

void completed(pdcomm::opcua::qt_client_response_ptr result)

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

매개변수

이름설명
resultcorrelation과 메타데이터를 포함한 공유 응답입니다.

failed

이벤트

요청 또는 워커가 실패했습니다. qt_client_failure를 참고합니다.

void failed(pdcomm::opcua::qt_client_failure failure)

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

매개변수

이름설명
failurecorrelation(워커이면 0), 상태, phase와 텍스트입니다.

maximum_commands

필드

큐에 있거나 전송 중인, 수락된 요청의 최대 개수입니다.

static constexpr size_t maximum_commands = 64

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

maximum_queued_bytes

필드

요청 하나의 최대 크기이자, 큐에 있고 아직 전송되지 않은 요청 전체를 합한 최대 크기입니다(4 MiB).

static constexpr size_t maximum_queued_bytes = 4 * 1024 * 1024

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

operator=

메서드

복사 대입을 할 수 없습니다.

qt_client_worker& operator=(const qt_client_worker&) = delete

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

pending

이벤트

요청이 서버로 전송되었습니다.

void pending(quint64 correlation, quint32 native_request_id)

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

매개변수

이름설명
correlation요청의 애플리케이션 상관 ID(correlation)입니다.
native_request_id네이티브 요청 ID(requestHandle)입니다.

qt_client_worker

생성자

복사할 수 없습니다.

qt_client_worker(const qt_client_worker&) = delete

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

qt_client_worker

생성자

워커를 만듭니다. start()가 연결을 시작합니다.

explicit qt_client_worker(qt_client_configuration configuration, QObject* parent = nullptr)

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

매개변수

이름설명
configuration설정입니다. fromRawData 배열과 비밀 정보를 포함한 모든 멤버를 새 할당 메모리로 복사합니다.
parent선택 사항인 QObject 부모입니다.

참고

  • 예외 error: 엔드포인트, 애플리케이션 URI 또는 사용자 이름이 4096바이트를 넘거나, 인증서나 키가 64 KiB를 넘거나, 사용자 비밀 정보가 16 KiB를 넘으면 #PDCOMM_OPCUA_LIMIT과 함께 던집니다.

ready

이벤트

세션이 활성화되었고 요청을 보내고 있습니다.

void ready(quintptr native_owner_thread)

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

매개변수

이름설명
native_owner_thread네이티브 클라이언트를 소유한 워커 스레드의 QThread::currentThreadId()입니다.

request_stop

메서드

워커에 멈추도록 요청합니다. 스레드 안전합니다.

void request_stop(qt_client_stop mode = qt_client_stop::drain)

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

이후 submit() 호출은 #PDCOMM_OPCUA_CLOSED를 반환합니다. qt_client_stop::drain이면 워커는 수락된 요청을 모두 완료한 뒤 CloseSession을 보내고 채널을 닫습니다. qt_client_stop::abort이면 워커는 자신의 스레드에서 프로토콜 닫기 없이 클라이언트를 해제하고, 남은 요청을 phase "abort"로 실패시킵니다. abort 요청은 drain으로 낮춰지지 않습니다. QThread::requestInterruption()도 abort를 선택합니다.

워커는 네이티브 호출 사이에 요청을 확인합니다. 블로킹 중인 연결, 활성화, 닫기 또는 DNS 조회는 중단되지 않습니다.

매개변수

이름설명
modeqt_client_stop::drain(기본값) 또는 qt_client_stop::abort입니다.

stopped

이벤트

워커가 끝났습니다. 항상 한 번의 실행에서 마지막 시그널입니다.

void stopped(pdcomm::opcua::qt_client_terminal terminal)

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

매개변수

이름설명
terminal최종 카운터와 이유입니다.

submit

메서드

UA Binary 서비스 요청 하나를 큐에 넣습니다. 스레드 안전합니다.

int32_t submit(const QByteArray& request, quint64 correlation)

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

요청을 복사만 합니다. 호출한 스레드에서는 네이티브 호출이 실행되지 않으며, 네이티브 마지막 오류 텍스트도 바뀌지 않습니다. ready() 전에 제출한 요청은 활성화 후 제출 순서대로 전송됩니다. 수락된 요청은 워커가 실행되면 completed() 또는 failed() 시그널을 정확히 한 번 받습니다. correlation은 그 시그널이 올 때까지 예약된 상태로 남습니다.

매개변수

이름설명
requestclient::begin()과 같은 형식의 완전히 인코딩된 요청입니다. 복사됩니다.
correlation0이 아닌 애플리케이션 ID입니다. 아직 끝나지 않은 요청 사이에서 고유해야 합니다.

반환값

OPC UA StatusCode가 아닌 수락 상태입니다. #PDCOMM_OPCUA_OK, 빈 요청이나 correlation 0이면 #PDCOMM_OPCUA_INVALID_INPUT, 사용 중인 correlation이면 #PDCOMM_OPCUA_BUSY, 요청이 4 MiB를 넘거나 maximum_commands 또는 maximum_queued_bytes를 넘게 되면 #PDCOMM_OPCUA_LIMIT, request_stop() 후나 워커가 끝난 뒤이면 #PDCOMM_OPCUA_CLOSED입니다.

~qt_client_worker

메서드

중단을 요청하고, 스레드를 기다리고, 자격 증명을 지웁니다.

~qt_client_worker() override

선언 위치: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

대기는 협조적입니다. 블로킹 중인 연결, 활성화, 닫기 또는 DNS 조회가 먼저 끝나며, 이는 timeout_ms와 운영 체제에 의해 제한됩니다. 워커 자신의 스레드에서 워커를 소멸시키면 치명적 오류입니다.