MQTT abonelik seçenekleri, MQTT 5.0 ile gelen ve broker'ın mesajları size nasıl ileteceğini kontrol eden abonelik başına bayraklardır: kendi yayınlarınızı alıp almayacağınız, retain bayrağının korunup korunmayacağı ve abone olduğunuzda retained mesajların yeniden gönderilip gönderilmeyeceği. Bu yazının sonunda her seçeneğin ne yaptığını, hangi gerçek sorunları çözdüğünü ve JavaScript ile Python'da nasıl ayarlanacağını öğrenmiş olacaksınız.
Abonelik Seçenekleri Nerede Bulunur?
MQTT 3.1.1'de bir SUBSCRIBE paketi bir topic filtresi ve istenen QoS'u tutan bir bayt taşır. MQTT 5.0 bu baytı korur, ancak boştaki bitleri yeni seçenekler için kullanır. Bir SUBSCRIBE içindeki her topic filtresi kendi seçenek baytına sahiptir:
| Bitler | Seçenek | Değerler |
|---|---|---|
| 0–1 | Maximum QoS | 0, 1 veya 2 |
| 2 | No Local | 0 = kapalı, 1 = açık |
| 3 | Retain As Published | 0 = kapalı, 1 = açık |
| 4–5 | Retain Handling | 0, 1 veya 2 |
| 6–7 | Ayrılmış | 0 olmalı |
Seçenekler filtre başına olduğundan, tek bir istemci aynı pakette chat/room1 topic'ine No Local açık olarak, config/# topic'ine ise farklı bir retain davranışıyla abone olabilir. Tam tanımlar OASIS MQTT 5.0 spesifikasyonunda yer alır. Seçenekler yalnızca istemci protokol sürümü 5 ile bağlandığında mevcuttur; bir 3.1.1 bağlantısı bunları ifade edemez. Sürümün geri kalanı hakkında bilgi için MQTT 5 özellikleri genel bakışına göz atın.
Maximum QoS
Bu, MQTT 3.1.1'den bilinen QoS'tur; anlamını netleştirmek için yeniden adlandırılmıştır. Broker'ın bu abonelikte mesajları ileteceği en yüksek QoS'u ifade eder. Maximum QoS değeri 1 olan bir aboneliğe QoS 2 ile yayınlanan bir mesaj QoS 1 olarak ulaşır. QoS 0 ile yayınlanan bir mesaj hiçbir zaman yükseltilmez. MQTT QoS seviyeleri sizin için yeniyse önce o rehberi okuyun, çünkü iletimle ilgili sürprizlerin çoğu bu düşürme kuralından kaynaklanır.
No Local: Kendi Mesajlarınızı Almayı Durdurun
Varsayılan olarak bir istemci, aynı zamanda abone olduğu bir topic'e yayın yaparsa broker mesajı ona geri gönderir. No Local ayarlandığında broker, mesajı onu yayınlayan bağlantıya iletmez.
Tipik durumlar:
- Sohbet ve iş birliği uygulamaları. Her katılımcı
chat/room1topic'ine hem yayın yapar hem de abone olur. No Local olmadan her kullanıcı kendi mesajını iki kez görür: bir kez yerel arayüzden, bir kez de broker'ın yankısı olarak. - İki yönlü senkronizasyon.
devices/+/configüzerinde hem yayın yapan hem de dinleyen bir servis, aksi takdirde kendi güncellemelerini işler ve döngüye girebilir. - Köprüler. Aynı broker'a abone olup yeniden yayın yapan bir köprü mesaj döngüleri oluşturabilir; köprü tarafında No Local bu döngüleri kırar.
Akılda tutulması gereken iki kural var. No Local, client ID ile tanımlanan bağlantı başına çalışır; dolayısıyla aynı uygulamanın çalıştırdığı iki farklı istemci yine birbirlerinin mesajlarını alır. Ayrıca bir shared subscription'da ($share/...) No Local ayarlamak protokol hatasıdır, çünkü bir grup için "yerel" kavramının anlamı yoktur.
Retain As Published
Broker canlı bir mesajı abonelere iletirken, yayıncı ayarlamış olsa bile varsayılan olarak RETAIN bayrağını temizler. Bayrak yalnızca broker'ın yeni bir abonelik nedeniyle gönderdiği mesajlarda (depolanan retained message) ayarlıdır. Bu varsayılan davranış, abonelerin "bu depolanan son değer" ile "bu az önce oldu" arasında ayrım yapmasını sağlar.
Retain As Published açıkken broker, RETAIN bayrağını tam olarak yayıncının ayarladığı gibi korur. Buna esas olarak abone mesajları başka bir yere yeniden yayınlıyorsa ve retained durumunun korunması gerekiyorsa ihtiyaç duyarsınız:
- Retained durumu yansıtan broker'lar arası köprüler.
- Retained mesajları kendisi de dikkate alan ikinci bir sisteme ileten ağ geçitleri ve proxy'ler.
- Yayıncının gerçekte ne gönderdiğini göstermek isteyen hata ayıklama araçları.
Sıradan uygulama aboneleri için bu seçeneği kapalı bırakın.
Retain Handling: Retained Tekrarlarını Kontrol Edin
Retained mesajlar, bir istemci abone olduğunda ona gönderilir. Retain Handling bunun ne zaman olacağına karar verir:
| Değer | Davranış | Ne zaman kullanılır |
|---|---|---|
| 0 | Her abonelikte retained mesajları gönder (varsayılan) | Mevcut duruma ihtiyaç duyan panolar ve tüketiciler |
| 1 | Retained mesajları yalnızca abonelik daha önce yoksa gönder | Yeniden bağlanırken tekrar abone olan, kalıcı oturumlu istemciler |
| 2 | Bu abonelik için retained mesajları asla gönderme | Yalnızca yeni mesajlarla ilgilenen olay işleyiciler |
Değer 1 ince bir sorunu çözer. Kalıcı oturuma sahip bir cihaz yeniden bağlanır ve önlem olarak tekrar abone olur. Değer 0 ile her retained mesajı yeniden alır; bunlar yapılandırma mesajlarıysa onları yeniden uygulayabilir. Değer 1 ile broker, retained mesajları yalnızca abonelik gerçekten yeniyse tekrar gönderir.
Değer 2, günlükleyiciler ve alarm servisleri için kullanışlıdır. Bir alarm servisi alarms/# topic'ine abone olursa ve broker saatler öncesinden kalma retained alarmlar tutuyorsa, değer 0 servisin her yeniden başlatıldığında eski alarmları tetiklemesine neden olur.
MQTT Abonelik Seçeneklerini Kodda Ayarlamak
Her iki örnek de broker.connectmq.com adresindeki herkese açık test broker'ına TLS üzerinden MQTT 5 ile bağlanır. Kendinize ait benzersiz bir topic öneki kullanın; herkese açık alan herkes tarafından okunabilir, bu yüzden veriyi zararsız tutun.
MQTT.js (Node.js)
// npm install mqtt
const mqtt = require("mqtt");
const prefix = "connectmq/demo/c41e";
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
clientId: "subopts-js-c41e",
protocolVersion: 5,
});
client.on("connect", () => {
// No Local: kendi sohbet mesajlarımızı bize geri yansıtma
client.subscribe(`${prefix}/chat/room1`, { qos: 1, nl: true }, (err, granted) => {
if (err) return console.error(err);
console.log("chat granted:", granted);
client.publish(`${prefix}/chat/room1`, "hello from js", { qos: 1 });
});
// Retain Handling 2: depolanan alarmları yok say, yalnızca yenileri al
client.subscribe(`${prefix}/alarms/#`, { qos: 1, rh: 2 });
// Retain As Published: RETAIN bayrağını gönderildiği gibi koru
client.subscribe(`${prefix}/config/#`, { qos: 1, rap: true, rh: 1 });
});
client.on("message", (topic, payload, packet) => {
console.log(`${topic} retain=${packet.retain} -> ${payload.toString()}`);
});
Betiği çalıştırdığınızda "hello from js" yazısını görmezsiniz, çünkü No Local yankıyı bastırır. Aynı sohbet topic'ine başka bir istemciden yayın yaptığınızda mesaj görünür.
Python paho-mqtt 2.x
import ssl
import paho.mqtt.client as mqtt
from paho.mqtt.subscribeoptions import SubscribeOptions
PREFIX = "connectmq/demo/c41e"
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print("Connect failed:", reason_code)
return
client.subscribe([
(f"{PREFIX}/chat/room1", SubscribeOptions(qos=1, noLocal=True)),
(f"{PREFIX}/alarms/#", SubscribeOptions(
qos=1, retainHandling=SubscribeOptions.RETAIN_DO_NOT_SEND)),
(f"{PREFIX}/config/#", SubscribeOptions(
qos=1, retainAsPublished=True,
retainHandling=SubscribeOptions.RETAIN_SEND_IF_NEW_SUB)),
])
def on_subscribe(client, userdata, mid, reason_code_list, properties):
print("SUBACK:", [str(rc) for rc in reason_code_list])
def on_message(client, userdata, msg):
print(f"{msg.topic} retain={msg.retain} -> {msg.payload.decode()}")
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id="subopts-py-c41e", protocol=mqtt.MQTTv5)
client.tls_set(cert_reqs=ssl.CERT_REQUIRED)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_message = on_message
client.connect("broker.connectmq.com", 8883, keepalive=60)
client.loop_forever()
Davranışı Doğrulamak
Birkaç dakikada çalıştırabileceğiniz hızlı bir test planı:
- Herhangi bir istemciden, örneğin ConnectMQ portalındaki tarayıcı içi MQTT istemcisinden veya
mosquitto_pub -rile,connectmq/demo/c41e/alarms/pump1topic'ine retained bir mesaj yayınlayın. - Python betiğini başlatın. Alarm aboneliği Retain Handling 2 kullandığından retained alarm iletilmez.
- Retained olmayan yeni bir alarm yayınlayın. Hemen ulaşır.
.../config/ratetopic'ine retained bir mesaj yayınlayın. Retain As Published açık olduğundan betik canlı mesaj içinretain=Trueyazdırır.- Başka hiçbir şeyi değiştirmeden betiği yeniden başlatın ve davranışın tekrarlanabilir olduğunu doğrulayın.
Yaygın Hatalar
- MQTT 3.1.1 ile bağlanmak. Kütüphaneler 3.1.1 bağlantısında abonelik seçeneklerini sessizce yok sayar. Her zaman
protocolVersion: 5veyaprotocol=mqtt.MQTTv5ayarlayın. - Shared subscription'larda No Local. Broker bunu protokol hatası olarak değerlendirir ve bağlantıyı kapatır.
- Retain Handling 1'in temiz oturumlarla çalışmasını beklemek. Oturum her seferinde yeniyse her abonelik de yenidir; bu yüzden değer 1, değer 0 gibi davranır.
- Panolarda Retain As Published kullanmak. Bu durumda pano depolanan bir değeri yenisinden ayırt edemez. Mesajları iletmiyorsanız varsayılanı koruyun.
- SUBACK'i görmezden gelmek.
0x80veya0x87gibi bir reason code, aboneliğin reddedildiği anlamına gelir. SUBACK reason code'larını günlüğe kaydedin.
Role Göre Seçenek Seçimi
| İstemci rolü | Max QoS | No Local | Retain As Published | Retain Handling |
|---|---|---|---|---|
| Pano | 1 | kapalı | kapalı | 0 |
| Sohbet katılımcısı | 1 | açık | kapalı | 0 veya 2 |
| Alarm servisi | 1 | kapalı | kapalı | 2 |
| Kalıcı oturumlu cihaz | 1 | kapalı | kapalı | 1 |
| Köprü veya yönlendirici | 2 | açık | açık | 0 |
Bu seçenekler, ConnectMQ ve diğer MQTT 5 broker'larını 3.1.1 öncüllerine göre üzerine geliştirme yapmayı kolaylaştıran unsurlardan biridir: eskiden uygulama düzeyinde filtreleme gerektiren davranış artık SUBSCRIBE paketindeki bir bayraktır. Bunları MQTT wildcard'ları yazısındaki iyi topic tasarımıyla birleştirin ve temelleri hâlâ öğreniyorsanız MQTT eğitimini elinizin altında tutun.
ConnectMQ ile Başlayın
Abonelik seçeneklerini herkese açık MQTT test broker'ı üzerinde test edin, ardından MQTT 5.0, TLS ve oluşturulmuş kimlik bilgileriyle özel bir yönetilen MQTT broker'a geçin. app.connectmq.com adresinde kredi kartı gerekmeden ücretsiz bir Serverless broker oluşturun.
Sık Sorulan Sorular
MQTT abonelik seçenekleri MQTT 3.1.1'de mevcut mu?
Hayır. MQTT 3.1.1 yalnızca istenen QoS'u taşır. No Local, Retain As Published ve Retain Handling bir MQTT 5.0 bağlantısı gerektirir.
Her abonelik seçeneğinin varsayılan değeri nedir?
No Local ve Retain As Published varsayılan olarak kapalıdır; Retain Handling ise varsayılan olarak 0'dır ve her abonelikte retained mesajları gönderir. Bu, MQTT 3.1.1 davranışıyla örtüşür.
No Local etkinken neden hâlâ kendi mesajlarımı alıyorum?
MQTT 5 ile bağlandığınızı ve yayıncı ile abonenin aynı bağlantı olduğunu kontrol edin. Aynı süreç içinde olsa bile ikinci bir istemci yerel sayılmaz.
Abonelikten çıkmadan abonelik seçeneklerini değiştirebilir miyim?
Evet. Aynı topic filtresi için yeni bir SUBSCRIBE göndermek, mevcut aboneliğin seçeneklerini değiştirir. Retain Handling 1 ile abonelik zaten var olduğundan retained mesajlar yeniden gönderilmez.



