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

세션, Keep Alive, Will

TCP 연결과 MQTT 세션(session)은 다릅니다. 연결은 끊겼다 다시 맺을 수 있지만, 세션은 연결이 끊긴 뒤에도 브로커와 클라이언트에 남을 수 있습니다.

MQTT 5.0 §4.1은 세션에 다음 상태가 들어간다고 정합니다.

위치 상태
브로커 클라이언트의 구독, 아직 확인되지 않은 QoS 1과 QoS 2 메시지, 클라이언트가 연결되어 있지 않은 동안 쌓인 메시지, Will 메시지
클라이언트 브로커가 아직 확인하지 않은 QoS 1과 QoS 2 메시지, 브로커에서 받아 완료하지 않은 QoS 2 메시지

세션이 남아 있으면 다시 연결했을 때 구독을 새로 만들 필요가 없고, 연결이 끊긴 동안의 QoS 1과 QoS 2 메시지도 받을 수 있습니다.

MQTT 3.1.1과 5.0은 세션 수명을 다르게 표현합니다.

버전 필드 뜻
3.1.1 Clean Session = 1 (§3.1.2.4) 연결할 때 이전 세션을 버리고, 연결이 끊기면 세션도 버립니다.
3.1.1 Clean Session = 0 이전 세션을 이어 쓰고, 연결이 끊긴 뒤에도 세션을 보관합니다.
5.0 Clean Start (§3.1.2.4) 1이면 연결할 때 이전 세션을 버립니다. 시작만 정합니다.
5.0 Session Expiry Interval (§3.1.2.11.2) 연결이 끊긴 뒤 세션을 보관할 초 단위 시간입니다. 0이거나 없으면 연결이 끊길 때 세션이 끝납니다. 0xFFFFFFFF는 만료되지 않음을 뜻합니다.

MQTT 5.0에서 3.1.1의 Clean Session = 1과 같은 동작은 Clean Start = 1, Session Expiry Interval = 0입니다. CONNACK의 Session Present 플래그(§3.2.2.1.1)는 브로커가 이전 세션을 이어받았는지 알려 줍니다.

Keep Alive(§3.1.2.10)는 클라이언트가 CONNECT에 넣는 초 단위 간격입니다.

  • 클라이언트는 그 간격 안에 보낼 패킷이 없으면 PINGREQ를 보내고, 브로커는 PINGRESP로 답합니다.
  • 브로커는 Keep Alive의 1.5배 동안 아무 패킷도 받지 못하면 연결을 끊습니다.
  • 0이면 Keep Alive를 쓰지 않습니다.
  • MQTT 5.0 브로커는 CONNACK의 Server Keep Alive 속성(§3.2.2.3.14)으로 다른 값을 지정할 수 있습니다. 이때 클라이언트는 브로커 값을 따라야 합니다.

예를 들어 Mosquitto에 max_keepalive 4를 설정하면, Keep Alive 30초로 연결한 PDComm 시뮬레이터가 4초마다 PINGREQ를 보냅니다.

Received PINGREQ from pdcomm-opcua-sim-98736-17
Sending PINGRESP to pdcomm-opcua-sim-98736-17

Will 메시지(§3.1.2.5)는 클라이언트가 CONNECT에 미리 맡겨 두는 메시지입니다. 브로커는 클라이언트가 DISCONNECT 없이 사라졌을 때 이 메시지를 대신 발행합니다.

  • 정상적인 DISCONNECT(이유 코드 0x00) 뒤에는 발행하지 않습니다.
  • Keep Alive 시간 초과, 네트워크 단절, 프로세스 강제 종료 때 발행합니다.
  • MQTT 5.0의 Will Delay Interval(§3.1.3.2.2)을 쓰면 발행을 늦출 수 있습니다. 그 사이에 다시 연결하면 발행하지 않습니다.
  • MQTT 5.0 클라이언트는 이유 코드 0x04(Disconnect with Will Message)로 끊어 Will을 일부러 발행하게 할 수도 있습니다.

장비의 온라인 상태를 알리는 흔한 방법은 다음과 같습니다.

  1. 연결 직후 factory/line1/status에 online을 보존 메시지로 발행합니다.
  2. 같은 토픽에 offline을 Will 메시지로 맡기고 RETAIN을 1로 둡니다.
  3. 비정상 종료되면 브로커가 offline을 발행하고 보존 메시지도 offline으로 바뀝니다.

브로커는 클라이언트 식별자로 세션을 찾습니다. 이미 연결된 식별자로 다른 클라이언트가 연결하면 브로커는 기존 연결을 끊습니다(§3.1.4). MQTT 5.0 브로커는 이때 기존 클라이언트에 이유 코드 0x8E(Session taken over)를 보냅니다. 두 클라이언트가 같은 식별자를 쓰면 서로를 계속 끊어 내므로 식별자는 클라이언트마다 달라야 합니다.

항목 값
클라이언트 식별자 pdcomm-opcua-sim-<프로세스 ID>-<DataSetWriterId>
Clean Start 1
Session Expiry Interval 보내지 않음(0과 같음)
Keep Alive 30초. 브로커가 Server Keep Alive를 주면 그 값을 따릅니다.
Will 쓰지 않음
연결이 끊겼을 때 자동으로 다시 연결하지 않습니다. PubSub가 멈추고 상태에 마지막 오류가 남습니다.