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

구독

  • 시뮬레이터 서버에 클라이언트 세션을 열고 변수 두 개를 구독합니다.
  • 값을 바꾸고 Publish로 데이터 변경 알림을 받습니다.
  • 받은 알림을 확인하고 구독을 지웁니다.
  • 실습 환경의 apps 패키지와 환경 변수 OPCUA_APPS
  • 터미널 한 개

이 튜토리얼은 헤드리스 시뮬레이터에 JSON 명령을 한 줄씩 입력합니다. 한 프로세스 안에서 시뮬레이터 서버와 클라이언트가 함께 동작합니다. 응답도 한 줄씩 나옵니다. 성공하면 "ok":true와 result, 실패하면 "ok":false와 error가 있습니다. 포트, 시각, 세션 ID는 실행할 때마다 다릅니다.

헤드리스 시뮬레이터를 실행합니다.

터미널 창
"$OPCUA_APPS/bin/pdcomm-opcua-headless"

서버를 시작합니다. 기본 구성은 127.0.0.1의 빈 포트에서 듣습니다.

{"action":"server_start"}
{"ok":true,"result":{"audit":[],"endpoint":"opc.tcp://localhost:58927/pdcomm/simulator","error":null,"running":true,"secure":true,"sessions":0}}

같은 시뮬레이터의 클라이언트로 서버에 연결합니다. URL을 지정하지 않으면 자기 서버에 연결합니다. 기본 보안 정책은 None입니다.

{"action":"connect"}
{"ok":true,"result":{"connected":true,"identity":"anonymous","items":[],"mode":"None","pending_cancelled":0,"policy":"None","session":"ns=1;s=pdcomm.diagnostics/session/2bce1a9ad4fba143f97f8aad9fe8327a","subscription":null,"url":"opc.tcp://localhost:58927/pdcomm/simulator"}}

Simulator.Double과 Simulator.Counter를 게시 주기 250 ms로 구독합니다.

{"action":"subscribe","nodes":["ns=2;s=Simulator.Double","ns=2;s=Simulator.Counter"],"interval_ms":250}
{"ok":true,"result":{"items":[{"good":true,"handle":1,"monitored_item":1,"node":"ns=2;s=Simulator.Double","status":"Good (0x00000000)","subscription":1},{"good":true,"handle":2,"monitored_item":2,"node":"ns=2;s=Simulator.Counter","status":"Good (0x00000000)","subscription":1}],"subscription":1}}

시뮬레이터가 CreateSubscription으로 구독 1을 만들고, CreateMonitoredItems로 노드마다 MonitoredItem을 추가했습니다. handle은 클라이언트 핸들(clientHandle)이고 monitored_item은 서버가 정한 ID입니다. 같은 세션에서 다시 subscribe하면 같은 구독에 항목을 더합니다.

Simulator.Double에 12.5를 씁니다.

{"action":"write","node":"ns=2;s=Simulator.Double","type":"Double","value":12.5}
{"ok":true,"result":{"good":true,"node":"ns=2;s=Simulator.Double","status":"Good (0x00000000)"}}

Publish를 두 번 보냅니다.

{"action":"publish","count":2}
{"ok":true,"result":{"dropped":0,"notifications":[{"good":true,"handle":1,"kind":"data","node":"ns=2;s=Simulator.Double","sequence":1,"server_time":1791997609191,"source_time":1791997609053,"status":"Good (0x00000000)","type":"Double","value":0.0},{"good":true,"handle":2,"kind":"data","node":"ns=2;s=Simulator.Counter","sequence":1,"server_time":1791997609194,"source_time":1791997609055,"status":"Good (0x00000000)","type":"UInt32","value":1},{"good":true,"handle":1,"kind":"data","node":"ns=2;s=Simulator.Double","sequence":2,"server_time":1791997609441,"source_time":1791997609196,"status":"Good (0x00000000)","type":"Double","value":12.5}],"queued":3}}
  • 첫 알림 메시지("sequence":1)에는 구독을 만든 순간의 값이 들어 있습니다. MonitoredItem을 만들면 서버가 현재 값을 한 번 보냅니다.
  • 두 번째 메시지("sequence":2)에는 바뀐 값 12.5가 들어 있습니다.
  • source_time과 server_time은 Unix 밀리초입니다.
  • queued는 시뮬레이터가 보관 중인 알림 수입니다.

Simulator.Counter는 시뮬레이션 주기(기본 500 ms)마다 1씩 늘어납니다. 잠시 뒤 다시 Publish를 보냅니다.

{"action":"publish"}
{"ok":true,"result":{"dropped":0,"notifications":[{"good":true,"handle":2,"kind":"data","node":"ns=2;s=Simulator.Counter","sequence":3,"server_time":1791997609697,"source_time":1791997609555,"status":"Good (0x00000000)","type":"UInt32","value":2}],"queued":4}}

Publish 응답은 바뀐 값이 있으면 게시 주기마다, 없으면 keep-alive 주기(게시 주기의 3배) 안에 옵니다. keep-alive 응답에는 알림이 없습니다.

시뮬레이터가 보관한 알림 전체를 봅니다.

{"action":"notifications"}
{"ok":true,"result":{"dropped":0,"entries":[{"good":true,"handle":1,"kind":"data","node":"ns=2;s=Simulator.Double","sequence":1,"server_time":1791997609191,"source_time":1791997609053,"status":"Good (0x00000000)","type":"Double","value":0.0},{"good":true,"handle":2,"kind":"data","node":"ns=2;s=Simulator.Counter","sequence":1,"server_time":1791997609194,"source_time":1791997609055,"status":"Good (0x00000000)","type":"UInt32","value":1},{"good":true,"handle":1,"kind":"data","node":"ns=2;s=Simulator.Double","sequence":2,"server_time":1791997609441,"source_time":1791997609196,"status":"Good (0x00000000)","type":"Double","value":12.5},{"good":true,"handle":2,"kind":"data","node":"ns=2;s=Simulator.Counter","sequence":3,"server_time":1791997609697,"source_time":1791997609555,"status":"Good (0x00000000)","type":"UInt32","value":2}],"limit":1000}}

보관 한도(limit)는 1000개입니다. 넘치면 오래된 알림부터 버리고 dropped를 늘립니다. {"action":"notifications_clear"}로 비웁니다.

{"action":"unsubscribe"}
{"ok":true,"result":{"deleted":1,"status":"Good (0x00000000)"}}

구독이 없으면 Publish를 보낼 수 없습니다.

{"action":"publish"}
{"error":"No subscription exists","ok":false}

연결을 끊고 프로그램을 끝냅니다.

{"action":"disconnect"}
{"action":"shutdown"}
{"ok":true,"result":{"client_closed":null,"pubsub_stopped":false,"server_stopped":true}}

실패한 명령이 하나라도 있었으면 헤드리스 시뮬레이터는 종료 코드 1로 끝납니다. 이 튜토리얼은 일부러 실패한 Publish가 있으므로 종료 코드가 1입니다.

응답 원인과 조치
Publishing interval must be 50 to 10000 ms and three intervals below the timeout 게시 주기 세 번이 클라이언트 제한 시간(기본 5000 ms)보다 깁니다. 예를 들어 "interval_ms":2000은 거부됩니다. 주기를 줄이거나 client.timeout_ms를 늘립니다.
No subscription exists 구독을 만들기 전이나 지운 뒤에 publish를 보냈습니다.
The client is not connected connect 전에 명령을 보냈습니다.
Stop the endpoint before changing its configuration 연결된 상태에서 configure로 클라이언트 구성을 바꾸려 했습니다. disconnect 뒤에 바꿉니다.

GUI에서는 Subscriptions 탭에서 같은 작업을 합니다. 시뮬레이터 GUI를 참고합니다.