[실습] 라즈베리파이에서 MQTT 프로토콜 활용
필기자
2025-05-27 15:20
1,091
0
본문
라즈베리파이에서 MQTT 프로토콜 활용
목적
목차
1. MQTT 프로토콜





2. MQTT 프로토콜을 활용 실습

목적
- MQTT 프로토콜에 대해 알아본다.
- 라즈베리파이에서 MQTT 프로토콜을 활용한다.
목차
1. MQTT 프로토콜
2. MQTT 프로토콜을 활용 실습
2. MQTT 프로토콜을 활용 실습
1. MQTT 프로토콜
- MQTT 프로토콜 개요
- MQTT(Message Queuing Telemetry Transport)는 경량 메시지 전송 프로토콜
- 제한된 대역폭·저전력 환경에서도 효율적인 통신을 위해 설계
- MQTT 통신 계층 구조

- MQTT 메시지 캡슐화 과정

- MQTT 메세지(프로토콜) 구조

- Variable Header & Payload 실제 데이터 예시

- PUBLISH 메시지 바이트 구조 예시

- MQTT 메세지 타입
- Fixed Header 상위 4비트 값
- 1~14 타입(예 0001 : CONNET, 0011 : PUBLISH)

- MQTT QoS(2~1비트)

- MQTT 시스템 구성도 역할

구성 요소 | 구분 | 주요 역할 | 구독/발행 토픽 예시 |
---|---|---|---|
라즈베리파이 | Publisher | 센서 데이터 수집 후 MQTT 메시지 발행 | home/temperature , home/humidity |
MQTT Broker | 중개 서버 | 메시지 전달 중계, 토픽 기반 라우팅 | 포트: 1883 사용 |
모바일 앱 | Subscriber | 실시간 모니터링 | home/+ |
웹 대시보드 | Subscriber | 시각화 및 대시보드 제공 | home/# |
데이터베이스 | Subscriber | 센서 데이터 저장 | home/temperature , home/humidity |
- HTTP / WebSocket / MQTT 비교
항목 | HTTP | WebSocket | MQTT |
---|---|---|---|
통신 구조 | 요청-응답 (Client → Server) | 양방향 (Client ↔ Server) | 퍼블리셔-서브스크라이버 (중앙 브로커 기반) Publisher-Subscriber (Broker) |
연결 방식 | 단일 요청마다 연결 (비연속 연결) | HTTP 최초 연결 후 지속 연결 (연결 유지) WebSocket 별도 프로토콜 전환 |
지속 연결 (TCP 기반, KeepAlive 사용) |
헤더 크기 | 큼 (수십~수백 바이트 이상) | 초기 HTTP 핸드셰이크 후 간결 | 매우 작음 (2바이트부터 시작) |
전송 방식 | 텍스트 기반 (JSON, HTML 등) | 바이너리 또는 텍스트 프레임 | 바이너리 메시지 기반 (주로 센서 데이터) |
QoS (신뢰성) | 없음 (전송 실패 시 재요청 필요) | 기본 TCP 신뢰성 | 3단계 QoS (0:최소, 1:1회, 2:정확히 1회) |
실시간성 | 낮음 (요청마다 오버헤드 발생) | 높음 (지속 연결 + 이벤트 기반 수신) | 매우 높음 (경량 + 지속 연결 + 이벤트 기반) |
방화벽/프록시 | 친화적 (80/443 포트 사용) | 대부분 가능 (HTTP 핸드셰이크 기반) | 제한 있음 (1883, 8883 포트 차단될 수 있음) |
보안 | HTTPS 사용 (TLS over 443) | WSS 사용 가능 (WebSocket over TLS) | TLS 가능 (MQTTS, 포트 8883) |
오버헤드 | 큼 (헤더 + 매 요청 연결/종료) | 중간 (초기만 큼, 이후 작음) | 작음 (헤더 최소, 고정 연결) |
확장성 | 좋음 (전 세계 웹 호환) | 제한적 (서버 처리량 제약 존재) | 좋음 (브로커 확장 가능, 클러스터링) |
적용 분야 | 웹 API, RESTful 서비스, 게시판 등 | 실시간 채팅, 온라인 게임, 스트리밍 등 | IoT 센서 네트워크, 스마트홈, 저전력 장치 |
의존성 구조 | 클라이언트-서버 직접 | 클라이언트-서버 직접 | 브로커를 통한 중개 통신 |
대표 포트 | 80 (HTTP), 443 (HTTPS) | 80 (WS), 443 (WSS) | 1883 (MQTT), 8883 (MQTTS) |

- HTTP Handshake
- SYN : Synchronize
- SYN-ACK : Synchronize - Acknowledgment
- TLS : Transport Layer Security





- KeepAlive : “연결이 살아있다”는 것을 확인하기 위해 주기적으로 소량의 패킷(핑)을 보내는 기능
- 1. 클라이언트 → 브로커: PINGREQ (연결 확인 요청[0xC0 0x00, 192 0])
- 2. 브로커 → 클라이언트: PINGRESP (연결 확인 응답[0xD0 0x00, 208 0])
- 3. 설정된 시간 간격으로 반복 실행(예, 60초)
- 1. 클라이언트 → 브로커: PINGREQ (연결 확인 요청[0xC0 0x00, 192 0])
2. MQTT 프로토콜을 활용 실습
- 시스템 구성도

- Mosquitto 브로커 설치
- MQTT 프로토콜을 구현한 오픈소스 메시지 브로커
- 특징
- 경량(Lightweight): 라즈베리파이 등 저사양 환경에서도 사용 가능
- QoS 지원: 메시지 전송 신뢰도 설정 가능 (QoS 0, 1, 2)
- Pub/Sub 구조: 퍼블리셔-서브스크라이버 간 직접 통신 없음
- 센서(라즈베리파이)→ 브로커(라즈베리파이) → 구독자(PC)
- 와일드카드: +, #로 토픽 구독 범위 지정
- + : 한 단계 토픽 대체 (예: home/+/temperature)
- # : 여러 단계 포함 (예: home/#)
- 다양한 언어 클라이언트 지원: Python, C, Java 등
- TLS/암호화 지원: 보안 통신 가능 (옵션)
- 포트
- 1883: 기본 MQTT 포트 (비암호화)
- 8883: TLS 암호화 MQTT
sudo apt update
sudo apt install -y mosquitto mosquitto-clients
sudo systemctl enable mosquitto
sudo systemctl start mosquitto
- MQTT 외부 접속 허용
sudo nano /etc/mosquitto/mosquitto.conf
#제일 하단에 다음 추가
# 외부 접속 허용
listener 1883 0.0.0.0
allow_anonymous true
#저장후 MQTT브로커 재시작
sudo systemctl restart mosquitto
- socket.io 서버 프로그램 수정
- paho-mqtt 라이브러리 설치
- iot_socket.py 파일 수정
(iot) pi@pi20221234:~/iot $ pip install paho-mqtt
import time
import threading
from flask import Flask, request
from flask_socketio import SocketIO
import RPi.GPIO as GPIO
import board
import adafruit_dht
import paho.mqtt.client as mqtt #추가
# --- MQTT 클라이언트 설정 ---
def on_connect(client, userdata, flags, rc):
print("MQTT 연결됨:", rc) # MQTT 브로커에 연결되면 호출되는 콜백 함수
mqtt_client = mqtt.Client(protocol=mqtt.MQTTv311) # MQTT 클라이언트 객체 생성 (v3.1.1 프로토콜 명시)
mqtt_client.on_connect = on_connect # 연결 콜백 등록 → 경고 방지 및 상태 확인용
mqtt_client.reconnect_delay_set(min_delay=1, max_delay=30) # 재연결 지연 시간 설정 (최소 1초, 최대 30초)
mqtt_client.connect_async("localhost", 1883, 60) # 비동기 방식으로 Mosquitto 브로커에 연결 시도
mqtt_client.loop_start() # 내부 네트워크 루프 실행 (백그라운드 스레드에서 처리)
# --- 글로벌 변수 ---
latest_temp = None
latest_hum = None
# --- GPIO 설정 ---
LED_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_PIN, GPIO.OUT)
# --- Flask-SocketIO 설정 ---
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*", async_mode="eventlet")
# --- DHT22 센서 설정 ---
dht_device = adafruit_dht.DHT22(board.D18)
# --- LED 상태 반환 함수 ---
def get_led_state():
return "on" if GPIO.input(LED_PIN) else "off"
# --- LED 제어 처리 ---
@socketio.on("led_control")
def control_led(data):
state = data.get("state")
if state == "on":
GPIO.output(LED_PIN, GPIO.HIGH)
elif state == "off":
GPIO.output(LED_PIN, GPIO.LOW)
state = get_led_state()
print(f"led 상태 : {state}")
socketio.emit("led_status", {"state": state})
# --- LED 상태 요청 처리 ---
@socketio.on("get_led_status")
def handle_status_request():
state = get_led_state()
print(f"led 상태 : {state}")
socketio.emit("led_status", {"state": state}, room=request.sid)
# --- 온습도 상태 요청 처리 ---
@socketio.on("get_temperature_humidity_status")
def send_temperature_humidity_status():
ret_temp_hum = {"temp": "N/A", "hum": "N/A"}
if latest_temp is not None and latest_hum is not None:
ret_temp_hum = {"temp": latest_temp, "hum": latest_hum}
socketio.emit("temperature_humidity_status", ret_temp_hum, room=request.sid)
# --- 센서 측정 스레드 ---
def temperature_monitor_thread():
global latest_temp, latest_hum
while True:
try:
temp = dht_device.temperature
hum = dht_device.humidity
if hum is not None and temp is not None:
latest_temp = round(temp, 1)
latest_hum = round(hum, 1)
print(f"센서 측정: {latest_temp}℃ / {latest_hum}%")
# MQTT 퍼블리시
#mqtt_client.publish("home/temperature", str(latest_temp), qos=1)
#mqtt_client.publish("home/humidity", str(latest_hum), qos=1)
mqtt_client.publish("home/temperature", str(latest_temp))
mqtt_client.publish("home/humidity", str(latest_hum))
else:
print("센서 데이터 없음")
except RuntimeError as e:
print("센서 에러:", e.args[0])
except Exception as e:
dht_device.exit()
raise e
time.sleep(2)
# --- 센서 스레드 시작 ---
def start_sensor_thread():
t = threading.Thread(target=temperature_monitor_thread)
t.daemon = True
t.start()
# --- 메인 ---
if __name__ == "__main__":
print("서버 시작")
start_sensor_thread()
socketio.run(app, host="0.0.0.0", port=5000)
- mqtt_client.publish() 주요 인자
- 사용법 : mqtt_client.publish("sensor/temp", "25.4", qos=1, retain=True)
인자명 | 자료형 | 설명 |
---|---|---|
topic |
str |
퍼블리시할 토픽 경로 |
payload |
str or bytes |
전송할 메시지 내용 |
qos |
int |
QoS 레벨 (0, 1, 2) |
retain |
bool |
True 이면 브로커가 마지막 메시지를 저장 (기본값: False ) |
properties |
Properties |
MQTT 5.0 속성 (선택사항) |
- 라즈베리파이 내에서 MQTT 클라이언트 구독
mosquitto_sub -h localhost -t "home/#" -v

- 윈도우PC 에서 구독
- https://mqtt-explorer.com/ 윈도우 install용 다운로드
- 설치 후 실행 -> 설정 -> 연결 -> 확인


댓글목록0