๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๐ŸŒฎ ๐Ÿ’ฌ
๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป/python

MQTT Keep Alive

by ๋ฐ”์ฟ„๋ฆฌ 2025. 3. 12.

 

์ตœ๊ทผ์— MQTT ํ†ต์‹  ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ Keep Alive ์„ค์ •์— ๊ด€๋ จํ•œ ๋ฌธ์ œ๋ฅผ ๊ฒช์—ˆ๋‹ค.

 

Status Update ํ•˜๋Š” mqtt ํด๋ผ์ด์–ธํŠธ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ƒ์„ฑํ•˜๊ณ 

send_status ๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ–ˆ๋‹ค.

 

import paho.mqtt.client as mqtt
import uuid
import time

class RobotStatusUpdater:
    def __init__(self, broker_ip, topic="robot/status"):
        self.client = mqtt.Client(f"Robot_Status_Updater_{uuid.uuid4()}")
        self.client.connect(broker_ip, 1883)
        self.topic = topic
        self.client = None

    def send_status(self, client, queue):
        while True:
            message = queue.get()
            if message is None:
                break
            client.publish('robot/status', message, qos=1)
            time.sleep(0.5)

status_updater = RobotStatusUpdater("127.0.0.1")

def send_status(message):
    status_updater.send_status(message)

 

์ฒ˜์Œ์— ํ˜ธ์ถœํ–ˆ์„ ๋•

ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ธŒ๋กœ์ปค์— ๋ฉ”์‹œ์ง€๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณด๋ƒˆ๋‹ค.

๊ทผ๋ฐ ์–ด๋Š ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋ฉ”์‹œ์ง€ ์ „์†ก์— ์‹คํŒจํ–ˆ๋‹ค.

 

ํ•œ๋ฒˆ ์—ฐ๊ฒฐ์„ ํ•˜๋ฉด ๊ณ„์† ์ง€์†๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ณ  ๊ทธ ๊ฑธ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ๋ฐœ์„ ํ–ˆ๋Š”๋ฐ ..

๋ถ„๋ช… ๋‚ด๊ฐ€ ๋น ๋œจ๋ฆฐ ๋ฌด์–ธ๊ฐ€๊ฐ€ ์žˆ๋‹ค ์ƒ๊ฐํ•˜๊ณ  Mqtt ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฝ์—ˆ๋‹ค.

 

๋‚ด๊ฐ€ ๋น ๋œจ๋ฆฐ ๊ฑด loop๋กœ ์‹คํ–‰ํ•˜๊ธฐ, ๊ทธ๋ฆฌ๊ณ  Keep Alive ์™€ PINGREQ.

 

๊ทธ๋ž˜์„œ ๊ณ ์นœ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค

import paho.mqtt.client as mqtt
import json
import time
from datetime import datetime

class RobotStatusUpdater:
    def __init__(self, broker_ip, topic="robot/status"):
        self.client = mqtt.Client("Robot_Status_Updater")
        self.client.connect(broker_ip, 1883, keepalive=120)
        self.topic = topic
        
    def connect_mqtt(self):
        """MQTT ๋ธŒ๋กœ์ปค์— ์—ฐ๊ฒฐํ•˜๊ณ  ์ž๋™ ์žฌ์—ฐ๊ฒฐ์„ ์„ค์ •"""
        try:
            self.client.connect(self.broker_ip, 1883)
            self.client.loop_start()  # ์ž๋™ ์žฌ์—ฐ๊ฒฐ ํ™œ์„ฑํ™”
            print(f"MQTT ์—ฐ๊ฒฐ๋จ: {self.broker_ip}")
        except Exception as e:
            print(f"MQTT ์—ฐ๊ฒฐ ์‹คํŒจ: {e}")

    def check_connection(self):
        """์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ , ๋Š์–ด์กŒ๋‹ค๋ฉด ์žฌ์—ฐ๊ฒฐ"""
        while True:
            try:
                self.client.loop()  # ์—ฐ๊ฒฐ ์œ ์ง€ ์ฒดํฌ
                self.client.publish(self.topic, "ping")  # ํ…Œ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ์ „์†ก
            except Exception as e:
                print(f"์—ฐ๊ฒฐ ๋Š๊น€, ์žฌ์—ฐ๊ฒฐ ์‹œ๋„ ์ค‘... {e}")
                self.connect_mqtt()  # ์žฌ์—ฐ๊ฒฐ ์‹œ๋„
            time.sleep(10)  # 10์ดˆ๋งˆ๋‹ค ์—ฐ๊ฒฐ ์ƒํƒœ ํ™•์ธ

    def send_status(self, message):
        """MQTT ๋ฉ”์‹œ์ง€ ์ „์†ก"""
        try:
            self.client.publish(self.topic, message)
            print(f"[์ƒํƒœ ์ „์†ก๋จ]: {datetime.now()}")
        except Exception as e:
            print(f"์ƒํƒœ ์ „์†ก ์‹คํŒจ: {e}, ์žฌ์—ฐ๊ฒฐ ์‹œ๋„")
            self.connect_mqtt()

status_updater = RobotStatusUpdater("127.0.0.1")

# ์ฃผ๊ธฐ์ ์ธ ์—ฐ๊ฒฐ ์ƒํƒœ ํ™•์ธ์„ ์œ„ํ•œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ ์‹คํ–‰
import threading
connection_thread = threading.Thread(target=status_updater.check_connection, daemon=True)
connection_thread.start()

def send_status(message):
    """์™ธ๋ถ€์—์„œ ํ˜ธ์ถœํ•  ์ƒํƒœ ์ „์†ก ํ•จ์ˆ˜"""
    status_updater.send_status(message)

 

- ์šฐ์„  loop_start()๋กœ ์‹คํ–‰์‹œ์ผœ์„œ ์ž๋™์œผ๋กœ PINGREQ๋ฅผ ๋ณด๋‚ด์–ด ์—ฐ๊ฒฐ์„ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

- ์‚ฌ์‹ค ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ๋งˆ๋ฌด๋ฆฌ์ง€์–ด๋„ ๋˜์ง€๋งŒ ๋ถˆ์•ˆํ•˜๊ธฐ์— ์—ฐ๊ฒฐ์„ ์ง€์†ํ•˜๊ธฐ ์œ„ํ•ด 10์ดˆ์— ํ•œ๋ฒˆ์”ฉ ์ง์ ‘ ping์„ ๋ณด๋‚ด์ฃผ์—ˆ๋‹ค.

- ping๋ฅผ ๋ณด๋‚ด๋ฉด์„œ ์—ฐ๊ฒฐ์„ ํ™•์ธํ•˜๋„๋กํ•˜๊ณ , ์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ์—” ์žฌ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•˜๋„๋ก ์ถ”๊ฐ€ํ–ˆ๋‹ค.

- ์ด๋ ‡๊ฒŒ ๋ณ€๊ฒฝํ•˜๋‹ˆ, ๊ณ„~~~~~์† ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์–ด์„œ ํ†ต์‹ ์ด ์ž˜ ๋˜์—ˆ๋‹ค .. ํœดใ… ใ… ใ… ใ… ใ… ใ… ใ… ใ… ใ…  ํ‘ํ‘ํ‘

 

๊ณต์‹๋ฌธ์„œ์— ์ฝ๊ณ  ๋‚ด๊ฐ€ ๋†“์ณค๋˜ ๋ถ€๋ถ„๋“ค์„ ๊ณต๋ถ€ํ–ˆ๋‹ค.

 

MQTT Keep Alive Interval Explained With Examples

MQTT uses a keepalive mechanism for checking the status of the TCP/IP connection.On a quiet TCP/IP connection an MQTT client will send a PINGREQ at set intervals and expect to receive a PINGRESP.

www.steves-internet-guide.com

 

MQTT๋Š” TCP/IP ์—ฐ๊ฒฐ์„ ์‚ฌ์šฉํ•œ๋‹ค.

  • MQTT ํด๋ผ์ด์–ธํŠธ๋Š” TCP/IP๋ฅผ ํ†ตํ•ด ๋ธŒ๋กœ์ปค์™€ ์—ฐ๊ฒฐ๋œ๋‹ค.
  • ์ด ์—ฐ๊ฒฐ์€ ํ•ญ์ƒ ์—ด๋ ค ์žˆ๋Š” ์ƒํƒœ๋กœ ์œ ์ง€๋˜์–ด ์–ธ์ œ๋“ ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์†ก์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Keep Alive ๊ธฐ๋Šฅ

  • ์ผ์ • ์‹œ๊ฐ„ ๋™์•ˆ ๋ฐ์ดํ„ฐ๊ฐ€ ํ๋ฅด์ง€ ์•Š์œผ๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” PINGREQ(ํ•‘ ์š”์ฒญ) ๋ฉ”์‹œ์ง€๋ฅผ ๋ธŒ๋กœ์ปค๋กœ ์ „์†กํ•œ๋‹ค.
  • ๋ธŒ๋กœ์ปค๋Š” ์ด์— ๋Œ€ํ•ด PINGRESP(ํ•‘ ์‘๋‹ต) ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์ด ๊ณผ์ •์€ ์—ฐ๊ฒฐ์ด ์—ฌ์ „ํžˆ ํ™œ์„ฑ ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

Keep Alive Period (์œ ์ง€ ์‹œ๊ฐ„)

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์†ก์ˆ˜์‹ ํ•˜์ง€ ์•Š๋Š” ์ตœ๋Œ€ ํ—ˆ์šฉ ์‹œ๊ฐ„์„ ์˜๋ฏธํ•œ๋‹ค.
  • ์ด ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„๋ก ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด PINGREQ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ํ™•์ธํ•œ๋‹ค.
  • ๋ธŒ๋กœ์ปค๊ฐ€ ์ผ์ • ์‹œ๊ฐ„ ๋‚ด PINGRESP๋ฅผ ๋ณด๋‚ด์ง€ ์•Š์œผ๋ฉด ์—ฐ๊ฒฐ์ด ๋Š๊ธด ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•œ๋‹ค.

Python MQTT ํด๋ผ์ด์–ธํŠธ์—์„œ Keep Alive ์ฒ˜๋ฆฌ

  • Python MQTT ํด๋ผ์ด์–ธํŠธ(paho-mqtt)๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, PINGREQ ๋ฉ”์‹œ์ง€๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•  ํ•„์š” ์—†๋‹ค.
  • ์ด์œ : loop() ํ•จ์ˆ˜๊ฐ€ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ
  • Keep Alive ๊ฐ’์„ 20์ดˆ๋กœ ์„ค์ •ํ•œ ๊ฒฝ์šฐ, 20์ดˆ๋งˆ๋‹ค PINGREQ๋ฅผ ๋ณด๋‚ด๊ณ  PINGRESP๋ฅผ ๋ฐ›๋Š”๋‹ค.

Keep Alive๋Š” ์†ก์ˆ˜์‹ (TX/RX) ๋ชจ๋‘๋ฅผ ๊ณ ๋ คํ•œ๋‹ค.

  • MQTT Kwwp Alive๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ธŒ๋กœ์ปค์™€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ฃผ๊ณ ๋ฐ›์€(Control Packet) ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ ์ธก์ •๋œ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฃผ๊ธฐ์ ์œผ๋กœ ์†ก์‹ (Publish)๋งŒ ํ•˜๋ฉด Keep Alive ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋  ์ˆ˜ ์žˆ์–ด PINGREQ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ๋…(Subscribe) ํ›„ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ (Receive)ํ•˜๋ฉด, Keep Alive ํƒ€์ด๋จธ๊ฐ€ ์ดˆ๊ธฐํ™”๋œ๋‹ค.
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ฐœํ–‰(Publish)๊ณผ ์ˆ˜์‹ (Receive) ํ™œ๋™์ด ์ง€์†์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋ฉด PINGREQ๋ฅผ ๋ณด๋‚ผ ํ•„์š”๊ฐ€ ์—†์–ด์ง„๋‹ค.

MQTT ํ”„๋กœํ† ์ฝœ์˜ ๊ทœ์ • (MQTT-3.1.2-24)

  • Keep Alive๋ฅผ ์„ค์ •ํ–ˆ๋”๋ผ๋„,
  • ๋ธŒ๋กœ์ปค๊ฐ€ Keep Alive ์‹œ๊ฐ„์˜ 1.5๋ฐฐ ๋™์•ˆ ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์–ด๋–ค Control Packet๋„ ๋ฐ›์ง€ ๋ชปํ•˜๋ฉด
  • ๋„คํŠธ์›Œํฌ ์žฅ์• ๋กœ ๊ฐ„์ฃผํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ฐ•์ œ ์—ฐ๊ฒฐ ์ข…๋ฃŒ(MUST disconnect) ํ•ด์•ผ ํ•œ๋‹ค.
  • ์ด ๊ธฐ๋Šฅ์€ ๋„คํŠธ์›Œํฌ ์žฅ์•  ๊ฐ์ง€๋ฅผ ์œ„ํ•œ MQTT์˜ ๊ธฐ๋ณธ์ ์ธ ์•ˆ์ • ์žฅ์น˜์ด๋‹ค.

http://www.steves-internet-guide.com/mqtt-keep-alive-by-example/

Keep Alive ๋ฉ”์‹œ์ง€๋ฅผ ๋น„ํ™œ์„ฑํ™”

  • Keep Alive ๊ฐ’์„ 0์œผ๋กœ ์„ค์ •ํ•˜๋ฉด PINGREQ/PINGRESP ๋ฉ”์‹œ์ง€๊ฐ€ ์ „์†ก๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ด ๊ฒฝ์šฐ, ํด๋ผ์ด์–ธํŠธ๋Š” ๋ธŒ๋กœ์ปค๊ฐ€ ์—ฐ๊ฒฐ์„ ๊ฐ์ง€ํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์—†์ด ๊ณ„์† ์—ฐ๊ฒฐ๋œ๋‹ค.

Keep Alive ์‹œ๊ฐ„

  • ์‹œ๊ฐ„์„ ๋งค์šฐ ๊ธธ๊ฒŒ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ๋น„ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ๋‹ค.
  • 15๋ถ„ ์ด์ƒ ์•„๋ฌด๋Ÿฐ ๋ฐ์ดํ„ฐ ์†ก์ˆ˜์‹ ์ด ์—†์„ ๊ฒฝ์šฐ, ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•˜๊ณ  ํ•„์š”ํ•  ๋•Œ ๋‹ค์‹œ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค.
  • ์žฅ์‹œ๊ฐ„ ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•˜๋ฉด ๋ฆฌ์†Œ์Šค๋ฅผ ์†Œ๋น„ํ•˜๊ณ , ๋„คํŠธ์›Œํฌ ์ƒํƒœ๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

 

โœ… ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์ •๋ฆฌ๋ฅผ ํ•˜๋ฉด ...

 

Keep Alive ๊ฐ’์„ 20์ดˆ๋กœ ์„ค์ •ํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž

- ๊ทธ๋Ÿผ 20์ดˆ ๋‚ด์— ์ตœ์†Œ 1๊ฐœ์˜ Control Packet์ด ํ•„์š”ํ•˜๋‹ค.

- 20์ดˆ ํ›„ PINGREQ๋ฅผ ๋ณด๋‚ด์ง€ ์•Š์œผ๋ฉด, 30์ดˆ (20์ดˆ*1.5) ๋‚ด์— ์–ด๋–ค ๋ฐ์ดํ„ฐ๋„ ์ˆ˜์‹ ๋˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ๋ธŒ๋กœ์ปค๊ฐ€ ๊ฐ•์ œ ์—ฐ๊ฒฐ ์ข…๋ฃŒ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

- ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์†ก์ˆ˜์‹ ํ•˜๋ฉด PINGREQ ์—†์ด๋„ ์—ฐ๊ฒฐ ์œ ์ง€ ๊ฐ€๋Šฅํ•˜๋‹ค.