세션, 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 메시지도 받을 수 있습니다.
Clean Session과 Session Expiry
섹션 제목: “Clean Session과 Session Expiry”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
섹션 제목: “Keep Alive”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-17Sending PINGRESP to pdcomm-opcua-sim-98736-17Will 메시지
섹션 제목: “Will 메시지”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을 일부러 발행하게 할 수도 있습니다.
장비의 온라인 상태를 알리는 흔한 방법은 다음과 같습니다.
- 연결 직후
factory/line1/status에online을 보존 메시지로 발행합니다. - 같은 토픽에
offline을 Will 메시지로 맡기고 RETAIN을 1로 둡니다. - 비정상 종료되면 브로커가
offline을 발행하고 보존 메시지도offline으로 바뀝니다.
클라이언트 식별자 충돌
섹션 제목: “클라이언트 식별자 충돌”브로커는 클라이언트 식별자로 세션을 찾습니다. 이미 연결된 식별자로 다른 클라이언트가 연결하면 브로커는 기존 연결을 끊습니다(§3.1.4). MQTT 5.0 브로커는 이때 기존 클라이언트에 이유 코드 0x8E(Session taken over)를 보냅니다. 두 클라이언트가 같은 식별자를 쓰면 서로를 계속 끊어 내므로 식별자는 클라이언트마다 달라야 합니다.
PDComm 시뮬레이터의 설정
섹션 제목: “PDComm 시뮬레이터의 설정”| 항목 | 값 |
|---|---|
| 클라이언트 식별자 | pdcomm-opcua-sim-<프로세스 ID>-<DataSetWriterId> |
| Clean Start | 1 |
| Session Expiry Interval | 보내지 않음(0과 같음) |
| Keep Alive | 30초. 브로커가 Server Keep Alive를 주면 그 값을 따릅니다. |
| Will | 쓰지 않음 |
| 연결이 끊겼을 때 | 자동으로 다시 연결하지 않습니다. PubSub가 멈추고 상태에 마지막 오류가 남습니다. |