MQTT
MQTT는 "Message Queuing Telemetry Transport"의 약어로, 경량 통신 프로토콜이다.
MQTT는 주로 IoT(Internet of Things) 장치들 간에 효율적으로 메시지를 교환하기 위해 설계되었다.
이 프로토콜은 네트워크 대역폭이 제한된 환경에서도 효율적으로 동작하도록 고안되었다.
MQTT의 주요 특징은 다음과 같다.
- 간결하고 가벼움:
프로토콜 자체가 간결하며, Message Header의 크기가 작아 효율적인 네트워크 사용을 가능하게 한다. - Publisher-Subscriber Model:
MQTT는 Publisher(데이터를 전송하는 Client)와 Subscriber(데이터를 수신하는 Client)간의 통신을 위한 모델을 제공한다. Client는 Topic을 Subscribe하고, 해당 Topic으로 데이터를 전송하는 다른 클라이언트는 그 데이터를 수신한다. - QoS(Quality of Service) 레벨:
Message 전송 품질을 조절하기 위한 QoS 레벨을 제공한다.
이를 통해 메시지의 안정성과 전송 성능을 조절 할 수 있다. - 유연한 메시지 전송:
메시지를 지정된 Topic으로 전송하고, Client는 관심있는 Topic을 Subscribe함으로서 유연한 메시지 전송이 가능하다. - 접속성 및 끊김 처리:
Client는 Server에 지속적으로 연결되어 있지 않아도 되며, 연결이 끊어졌을 때 재접속을 처리할 수 있다.
MQTT는 다양한 IoT 분야에서 사용되며, 센서 데이터 전송, 원격 모니터링, 제어 시스템, 스마트 홈 등에서 효과적으로 활용 된다. 또한 MQTT Broker라 불리는 Middle Server를 통해 여러 Device간의 통신을 중재하는 형태로 사용되기도 한다.
MQTT Broker 란?
MQTT Broker(브로커)는 MQTT Protocol에서 중요한 역할을 하는 중간 매개체이다.
이 브로커는 MQTT 클라이언트 간에 메시지를 전달하고 관리하여 효율적이고 신뢰성 있는 통신을 지원한다.
MQTT 브로커의 주요 역할은 다음과 같다.
- 연결 관리:
MQTT 브로커는 클라이언트들 간의 연결을 허용하고 관리한다.
클라이언트가 브로커에 연결하면, 브로커는 해당 클라이언트를 식별하고 연결 상태를 유지한다. - 메시지 라우팅:
발행자(Publisher)가 메시지를 브로커에 발행하면, 브로커는 해당 메시지를 구독자(Subscriber)에 라우팅한다.
이를 통해 메시지가 목적지로 효율적으로 전달된다. - 토픽(Topic) 기반 라우팅:
MQTT는 Topic 기반 메시징을 지원하며, 브로커는 발행된 메시지를 특정 주제에 대해 구독한 클라이언트들에게 전달한다. - QoS 수준 관리:
브로커는 메시지의 Quality of Service(QoS) 수준을 관리한다.
QoS 수준에 따라 메시지의 전송 및 수신에 대한 확인과 보장 수준이 결정된다. - 유지 관리 및 라스트 월 처리:
브로커는 클라이언트들과의 연결을 관리하고, 연결이 끊어진 경우 클라이언트가 설정한 *라스트월 메시지를 처리한다. - 보안 및 인증:
MQTT 브로커는 보안 및 인증을 관리한다.
클라이언트가 브로커에 연결할 때 보안 프로토콜과 인증 매커니즘을 통해 안전한 통신을 보장한다. - 클러스터링:
일부 MQTT 브로커는 클러스터링을 지원하여 확장성과 가용성을 향상시킨다.
클로스터링을 통해 여러 브로커가 협력하여 메시지 전달 및 관리를 분산 시킬 수 있다. - 로그 및 모니터링:
브로커는 시스템 동작 로그를 기록하고, 현재 상태를 모니터링할 수 있는 기능을 제공한다.
MQTT 브로커는 IoT 시스템에서 핵심 구성 요소 중 하나로, 안정적이고 효율적인 메시징 서비스를 제공하여 디바이스 간 통신을 원할하게 한다.
- 라스트 윌
라스트 윌(Last Will) 메시지는 MQTT(MQ Telemetry Transport) 프로토콜에서 사용되는 개념으로,
클라이언트가 브로커에 연결되어 있지만 연결이 끊어진 경우에 자동으로 Publish 되는 Message를 나타낸다.
이 메시지는 클라이언트가 비정상적으로 연결을 종료했을 때 브로커에게 특정 주제에 대한 정보를 전달하는 데 사용된다.
라스트 윌 메시지는 클라이언트가 연결을 설정할 때 설정된다.
클라이언트는 브로커에게 라스트윌 메시지를 보내도록 지시하며, 이 메시지는 특정 Topic에 대해 Publish 된다.
일반적으로 라스트 윌 메시지에는 클라이언트의 상태 또는 다른 중요한 정보가 포함된다.
라스트 윌 메시지는 주로 다음과 같은 상황에서 유용하게 사용된다.
1. 비정상적인 연결 종료:
- 클라이언트가 예기치 않게 연결이 끊어진 경우에, 브로커는 설정된 라스트 윌 메시지를 해당 topc에 publish 하여 연결이 끊어진 클라이언트에 대한 정보를 기록할 수 있다.
2. 상태 업데이트:
- 클라이언트의 상태가 특정 이벤트에 따라 변경된 경우, 라스트 윌 메시지를 통해 해당 상태 업데이트를 브로커에게 알릴 수 있다.
라스트 윌은 일종의 안전 메커니즘으로, 클라이언트의 비정상적인 상태를 탐지하고 그에 따른 조치를 취할 수 있도록 도와준다.
- 클러스터링
클러스터링(Clustering)은 여러 컴퓨터 또는 서버가 함께 작동하여 하나의 시스템처럼 동작하는 컴퓨터 시스템의 구성을 나타낸다. 이는 성능 향상, 가용성 증가, 확장성 확보 등의 이점을 제공한다.
클러스터링은 여러 대의 서버가 협력하여 특정 작업을 수행하거나 서비스를 제공할 수 있는 방식으로 구성된다.
MQTT 브로커의 클러스터링은 여러 브로커가 함께 작동하여 메시지 브로커 서비스를 제공하는 구성을 나타낸다.
MQTT 브로커의 클러스터링은 대규모 또는 고가용성을 요구하는 환경에서 특히 유용하다.
클러스터링은 일반적으로 로드 밸런싱 및 상태 공유를 통해 구현된다.
각 브로커는 클러스터 내에서의 역할 및 상태에 대한 정보를 공유하며, 클러스터 전체에서 메시지를 조율하여 효과적으로 동작하게 된다.
MQTT Broker Program
- Eclipse Mosquitto:
- 오픈 소스로 제공되는 MQTT 브로커로, 경량이면서 안정적이며 확장성이 좋다.
- C언어로 작성되었으며, MQTT 3.1 및 3.1.1 표준을 지원한다.
- 다양한 플랫폼에서 실행 가능하며, 옵션 설정이 유연하다.
Mosquitto 설치 방법
anonymous false 가 default 보안관련..
보안관련
Mosquitto SSL(TLS) 설정, 인증서와 키 만들기
OpenSSL 설치..
발전시켜서 TLS 를 사용.
암호화할 때 사용할 key와 인증서를 만들어야됨.
개인키와 개인인증서를 만드는 방법.. (우리가 할것)
어디서 인증을 받았는지 인증기관에 대한 정보가 인증서에 들어가있음 certificate authority(ca) 에서 발급된게 맞는지 확인함.. 인터넷에서 보안소켓 공인인증기관(CA) 인증서에 누가 인증해줬는지 인증서버에 접속해서 진짜인지 아닌지 확인 이 서버가 발급한게 맞다는것이 확인됨. 인증서버를 통해 확인이 되었다면
이 서버가 보내준 public key를 암호화.. 값을 ......................................................
핵심은 인증서버임. 키도 인증서버를 통해 검증 | 인증서버를 쓰려면 돈을주고 사용해야됨.
테스트목적인데 인증서버에 등록하고 돈을 내기 어려우니.... 개발단계에서는 마지막으로 서비스시작시 인증서 발급 정식적으로 하고 자체적으로 할 때는 CA 대신으로 할 때는 self signed 을해야됨.
교재에 나오는 부분이 자체적으로 자체 인증서와 키를 만드는것
기능과 암호화도 똑같은데 차이점은 보증을 해주는 것과 아닌 것과 차이가 있는 것임.
openssl 을 사용함..
opensource로..
-- 이건 그냥 pass~
https://github.com/256dpi/arduino-mqtt
// This example uses an Adafruit Huzzah ESP8266
// to connect to shiftr.io.
//
// You can check on your device after a successful
// connection here: https://www.shiftr.io/try.
//
// by Joël Gähwiler
// https://github.com/256dpi/arduino-mqtt
#include <ESP8266WiFi.h>
#include <MQTT.h>
const char ssid[] = "ssid";
const char pass[] = "pass";
WiFiClient net;
MQTTClient client;
unsigned long lastMillis = 0;
void connect() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
while (!client.connect("arduino", "public", "public")) {
Serial.print(".");
delay(1000);
}
Serial.println("\nconnected!");
client.subscribe("/hello");
// client.unsubscribe("/hello");
}
void messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
// Note: Do not use the client in the callback to publish, subscribe or
// unsubscribe as it may cause deadlocks when other things arrive while
// sending and receiving acknowledgments. Instead, change a global variable,
// or push to a queue and handle it in the loop after calling `client.loop()`.
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, pass);
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported
// by Arduino. You need to set the IP address directly.
client.begin("public.cloud.shiftr.io", net);
client.onMessage(messageReceived);
connect();
}
void loop() {
client.loop();
delay(10); // <- fixes some issues with WiFi stability
if (!client.connected()) {
connect();
}
// publish a message roughly every second.
if (millis() - lastMillis > 1000) {
lastMillis = millis();
client.publish("/hello", "world");
}
}
bool connect(const char clientID[], bool skip = false);
bool connect(const char clientID[], const char username[], bool skip = false);
bool connect(const char clientID[], const char username[], const char password[], bool skip = false);
Serial.print("\nconnecting...");
while (!client.connect("arduino")) { // 1883(default)
// while (!client.connect("arduino", "public", "public")) { // 1884 (custom)
// while (!client.connect("arduino", "jake", "1234")) { // 1884 (custom)
Serial.print(".");
delay(1000);
}
bool subscribe(const String &topic);
bool subscribe(const String &topic, int qos);
bool subscribe(const char topic[]);
bool subscribe(const char topic[], int qos);
#include <ESP8266WiFi.h> // ESP8266WiFi 라이브러리
#include <MQTT.h> //MQTT 라이브러리
// Wi-Fi 및 MQTT 클라이언트 설정
// Wi-Fi 연결에 필요한 SSID와 비밀번호 설정
const char ssid[] = "SSID";
const char pass[] = "password";
WiFiClient net; // WiFiClient 객체 'net'
MQTTClient client; // MQTTClient 객체 'client'
unsigned long lastMillis = 0;
// 연결 함수 정의
// Wi-Fi 연결을 확인하고, 연결이 되지 않았다면 1초마다 점을 찍으면서 연결을 기다림
// 연결되면 '/hello' topic을 subscribe 한다.
void connect()
{
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(1000);
}
Serial.println("\nconnected!");
client.subscribe("/hello");
}
// 메시지 수신 Callback 함수 정의
// '/hello' topic 에서 메시지 수신시 해당 메시지를 Serial monitor에 출력
void messageReceived(String &topic, String &payload)
{
Serial.print("incoming: ");
Serial.print(topic);
Serial.print(" - ");
Serial.println(payload);
}
// setup
// Serial 통신을 시작하고, Wi-Fi에 연결하고 MQTT 클라이언트를 초기화한다.
// 또한 메시지를 수신하는 콜백함수를 등록하고, Wi-Fi와 MQTT 연결을 설정하는 connect 함수를 호출한다.
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid, pass);
client.begin("30.30.30.28", net);
client.onMessage(messageReceived);
connect();
}
// loop
// MQTT 클라이언트를 주기적으로 업데이트하고, 연결이 끊어졌다면 다시 연결을 시도한다.
// 또한 1초마다 '/hello' topic으로 "world"라는 메시지를 발행한다.
void loop()
{
client.loop();
if (!client.connected())
{
connect();
}
if (millis() - lastMillis > 1000)
{
lastMillis = millis();
client.publish("/hello", "world");
}
}
// 이 코드는 ESP8266을 사용하여 Wi-Fi와 MQTT를 이용한 간단한 통신을 구현한 것으로,
// 장치 간에 데이터를 주고 받을 때 사용될 수 있다.
+-------------------+ +----------------------+
| | | |
| Setup | | MQTT Client |
| | | |
+-------------------+ +----------------------+
| |
v v
+-------------------+ +----------------------+
| | | |
| Serial.begin | | client.begin |
| WiFi.begin | | client.onMessage |
| client.begin ---------->| connect |
| client.onMessage| | loop |
| connect | | ... |
| | +----------------------+
+-------------------+ |
| |
v |
+-------------------+ |
| | |
| Loop | |
| | |
+-------------------+ |
| |
v |
+-------------------+ |
| | |
| client.loop | |
| | |
| if (!connected) +-------------------------->+
| connect |
| |
+-------------------+
- setup:
- 시리얼 통신을 시작하고, Wi-Fi와 MQTT 클라이언트를 초기화한다.
- MQTT 클라이언트에 메시지를 수신할 때 호출할 콜백 함수를 등록한다.
- Wi-Fi에 연결되고 나면 "/hello" topic을 subscribe 한다.
- loop:
- MQTT 클라이언트를 주기적으로 업데이트 한다.
- 연결이 끊어졌다면 'connect' 함수를 호출하여 다시 연결을 시도한다.
- 1초마다 '/hello' topic으로 "world" 라는 message를 publish 한다.
- connect 함수:
- Wi-Fi 연결이 확인되지 않으면 1초마다 점을 찍으면서 기다린다.
- Wi-Fi에 연결되면 '/hello' topic을 구독한다.
'Network' 카테고리의 다른 글
Endpoint-related Configuration of a USB CDC Device (0) | 2024.02.21 |
---|---|
동일 IP 대역에서 장치간 네트워크 연결 상태 미확인 문제 트러블 슈팅 (0) | 2023.12.01 |
TCP Header(flag bit) (0) | 2023.05.19 |
tracert 와 pathping 과의 차이 (0) | 2023.05.19 |
SDN(Software Defined Networking, 소프트웨어 정의 네트워크) (0) | 2023.05.19 |