글 / MQTT 메시징

MQTT 세션 유지와 단절 중 메시지 수신

고정 Client ID, Clean Start 0, 세션 만료 시간, QoS 1 구독을 모두 갖추어야 단절 중의 메시지를 수신한다.

작성일 · 읽는 시간 2분 · MQTT 5.0 기준

문제 정의

구독자의 연결이 단절된 동안 발행된 메시지는 기본 설정에서는 그 구독자에게 전달되지 않는다. 브로커가 메시지를 보관했다가 이후에 전송하게 하려면 세션을 유지해야 한다.

세션은 브로커가 client id마다 유지하는 상태이다. 세션에는 구독 목록과, 그 클라이언트에게 전송하기 위해 대기 중인 QoS(전달 보장 수준) 1·2 메시지가 포함된다.

브로커가 client id마다 유지하는 세션의 구성

Clean Start와 Session Expiry Interval

  • Clean Start: 1이면 기존 세션을 폐기하고 새 세션을 시작한다. 0이면 같은 client id의 세션을 재개한다.
  • Session Expiry Interval: 연결이 닫힌 뒤 세션을 보관할 시간(초)이다. 지정하지 않거나 0이면 연결이 닫힐 때 세션도 종료된다.

이전 버전인 MQTT 3.1.1에서는 clean session 플래그 하나가 두 역할을 담당한다. 0이면 세션을 재개하고 연결이 종료된 뒤에도 보관하지만, 보관 기간은 지정할 수 없다.

Clean Start와 Session Expiry Interval의 세션 처리

필요 조건

  • client id 고정: 빈 id로 연결하면 브로커가 매번 새 id를 할당하므로 이전 세션을 찾지 못한다.
  • Clean Start 0과 0보다 큰 Session Expiry Interval.
  • 구독과 발행 모두 QoS 1 이상: 전달 QoS는 둘 중 낮은 값이고, 세션에 반드시 저장되는 것은 QoS 1·2 메시지이다.

단절 중에 발행된 메시지를 세션에 보관했다가 재연결 뒤 전송하는 순서

pythonsubscriber.py
import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes
from paho.mqtt.properties import Properties


def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe("plant/line1/+/alarm", qos=1)


client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id="line1-alarm-logger",
    protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect

# 끊긴 뒤 한 시간 동안 세션을 보관하게 한다
props = Properties(PacketTypes.CONNECT)
props.SessionExpiryInterval = 3600

client.connect("broker.example", 1883, clean_start=False, properties=props)
client.loop_forever()