MQTT wildcard'ları (joker karakterler), tek bir aboneliğin birçok topic ile eşleşmesini sağlar: + tam olarak bir topic seviyesiyle, # ise bir filtrenin sonunda herhangi sayıda seviyeyle eşleşir. Bu rehberde kesin eşleşme kurallarını, insanları tökezleten uç durumları ve her filtreyi iş başında görmek için herkese açık bir broker'a karşı çalıştırabileceğiniz bir dizi mosquitto_sub komutunu öğreneceksiniz.
Topic'ler ve Topic Filtreleri
Publisher'lar her zaman home/kitchen/temperature gibi somut bir topic adına publish eder. Subscriber'lar ise wildcard içerebilen bir topic filtresiyle abone olur. Broker gelen her topic'i her aboneliğin filtresiyle seviye seviye karşılaştırır ve mesajı eşleşen herkese teslim eder. Bu yönlendirme işi, bir MQTT broker'ının yaptığı işin özüdür.
Wildcard'lar yalnızca filtrelerde geçerlidir. + veya # içeren bir topic'e publish etmek protokol hatasıdır ve çoğu broker istemcinin bağlantısını keser.
Tek Seviyeli Wildcard: +
+, içeriği ne olursa olsun tam olarak bir seviyeyle eşleşir. Bir seviyenin tamamını kaplaması gerekir: home/+/temperature geçerlidir, home/kit+/temperature değildir.
| Filtre | Eşleşir | Eşleşmez |
|---|---|---|
home/+/temperature |
home/kitchen/temperature, home/garage/temperature |
home/temperature, home/kitchen/sensor1/temperature |
+/+/status |
site1/pump3/status |
site1/status, site1/hall/pump3/status |
home/+ |
home/kitchen |
home, home/kitchen/light |
+ |
home |
home/kitchen, /home |
İki ayrıntıyı hatırlamakta fayda var. Birincisi, + boş bir seviyeyle de eşleşir; yani home/+/temperature, home//temperature ile eşleşir. İkincisi, baştaki bir eğik çizgi boş bir ilk seviye oluşturur; dolayısıyla +/home, /home ile eşleşir. Her ikisi de makul MQTT topic adlandırma kurallarına uymak ve boş seviyelerden tamamen kaçınmak için iyi nedenlerdir.
Tek bir filtrede birden fazla + kullanabilirsiniz. factory/+/+/temperature, factory altında iki seviye aşağıdaki her sıcaklıkla eşleşir; bu da tek bir ölçümü tüm filo genelinde gösteren dashboard'lar için idealdir.
Çok Seviyeli Wildcard:
#, sıfır dahil herhangi sayıda seviyeyle eşleşir ve bir seviyenin tamamını kaplayarak filtrenin son karakteri olmalıdır.
| Filtre | Eşleşir | Eşleşmez |
|---|---|---|
home/# |
home, home/kitchen, home/kitchen/light/state |
office/kitchen |
home/kitchen/# |
home/kitchen, home/kitchen/temperature |
home/garage/temperature |
# |
$ ile başlamayan her topic |
$SYS/... |
home/+/light/# |
home/kitchen/light, home/kitchen/light/brightness |
home/light |
Geçersiz filtrelere örnek olarak home/#/temperature (# sonda değil), home# (tam bir seviye değil) ve home/kitchen# verilebilir.
home/# filtresinin üst topic olan home'un kendisiyle de eşleştiğine dikkat edin. Yalnızca alt topic'leri istiyorsanız home altında en az bir seviye gerektiren home/+/# kullanın.
Wildcard'lar ve $ Topic'leri
$SYS/broker/... gibi $ ile başlayan topic'ler broker bilgileri için ayrılmıştır. Spesifikasyon, bir wildcard ile (# veya +) başlayan bir filtrenin bunlarla eşleşmemesi gerektiğini söyler. Bunları okumak için örneğin $SYS/# ile açıkça abone olmanız gerekir. Bu, hata ayıklama amaçlı bir # aboneliğinin broker istatistikleriyle dolup taşmasını önler. Örneğin bir ConnectMQ broker'ında bağlantı durumu $SYS/broker/connection/{clientId}/state altında görünür. Ayrıntılar MQTT $SYS topic'leri yazısında.
MQTT Wildcard'larını Canlı Bir Broker'da Deneyin
Aşağıdaki deney broker.connectmq.com adresindeki herkese açık MQTT test broker'ını kullanır. Yalnızca kendi mesajlarınızı görmek için w1c5 değerini kendi rastgele dizenizle değiştirin ve herkese açık alan herkes tarafından okunabildiği için payload'ları zararsız tutun.
Önce, yeni subscriber'ların hemen alması için küçük, retained bir topic ağacı publish edin:
B="-h broker.connectmq.com -p 1883 -i wc-pub-w1c5 -r -q 1"
R="connectmq/demo/w1c5"
mosquitto_pub $B -t "$R/home/kitchen/temperature" -m 21.5
mosquitto_pub $B -t "$R/home/kitchen/humidity" -m 48
mosquitto_pub $B -t "$R/home/garage/temperature" -m 14.2
mosquitto_pub $B -t "$R/home/garage/door" -m closed
mosquitto_pub $B -t "$R/home" -m house-online
mosquitto_pub $B -t "$R/office/desk/temperature" -m 23.0
Şimdi her aboneliği çalıştırın ve çıktıları karşılaştırın (retained mesajlar göründükten sonra Ctrl+C):
S="-h broker.connectmq.com -p 1883 -i wc-sub-w1c5 -v"
R="connectmq/demo/w1c5"
# 1. Doğrudan bir odanın altındaki her sıcaklık
mosquitto_sub $S -t "$R/home/+/temperature"
# 2. Mutfaktaki her şey
mosquitto_sub $S -t "$R/home/kitchen/#"
# 3. home topic'inin kendisi dahil home altındaki her şey
mosquitto_sub $S -t "$R/home/#"
# 4. home'un kendisi değil, yalnızca alt topic'leri
mosquitto_sub $S -t "$R/home/+/#"
# 5. Herhangi bir bina ve odadaki sıcaklıklar
mosquitto_sub $S -t "$R/+/+/temperature"
Beklenen sonuçlar: 1. filtre iki topic döndürür; 2. filtre iki; 3. filtre home dahil beş; 4. filtre dört; 5. filtre ofis masası dahil üç topic döndürür.
İşiniz bittiğinde retain bayrağıyla boş payload'lar publish ederek retained mesajları temizleyin:
for t in home/kitchen/temperature home/kitchen/humidity home/garage/temperature \
home/garage/door home office/desk/temperature; do
mosquitto_pub -h broker.connectmq.com -p 1883 -i wc-clean-w1c5 -r -n \
-t "connectmq/demo/w1c5/$t"
done
Python'da Wildcard'lar
import paho.mqtt.client as mqtt
ROOT = "connectmq/demo/w1c5"
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe([(f"{ROOT}/home/+/temperature", 0),
(f"{ROOT}/home/garage/#", 1)])
def on_message(client, userdata, msg):
# Topic eşleştirme yardımcısı: bir topic'in hangi filtreye ait olduğunu kontrol et
if mqtt.topic_matches_sub(f"{ROOT}/home/+/temperature", msg.topic):
print("Temperature", msg.topic, msg.payload.decode())
else:
print("Garage", msg.topic, msg.payload.decode())
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="wc-py-w1c5")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_forever()
Filtrelerinizden ikisiyle eşleşen bir mesaj, broker'a bağlı olarak bir kez veya eşleşen her abonelik için bir kez teslim edilebilir; spesifikasyon her iki davranışa da izin verir. İşleyicilerinizi buna tolerans gösterecek şekilde tasarlayın.
Topic'leri Wildcard'ların İşinize Yarayacağı Şekilde Tasarlamak
Wildcard'lar ancak altlarındaki topic ağacı kadar faydalıdır. + ve # tüm seviyeler üzerinde çalıştığından, seviye sırasına dair her karar bir subscriber'ın hangi soruları zahmetsizce sorabileceğini belirler. Birkaç kalıp defalarca karşılığını verir.
En sık filtrelediğiniz boyutu başa yakın koyun. Operatörler genellikle tek seferde bir tesise bakıyorsa, tesis topic'in başlarında yer almalıdır; böylece acme/berlin/# onu tek bir filtreyle yakalar. Genellikle tek bir ölçümü tüm tesisler arasında karşılaştırıyorlarsa, ölçümü son seviye olarak tutun ki acme/+/+/+/temperature çalışsın.
Derinliği tutarlı tutun. acme/+/+/status gibi bir filtre, her cihazın namespace'in tam olarak iki seviye altında bulunduğunu varsayar. Bazı cihazlar bir seviye daha derinde yer alıyorsa, bu filtre üzerine kurulan her dashboard'dan sessizce düşerler. Tutarlı derinlik +'yı öngörülebilir kılar.
Mesaj kategorilerini kendi seviyelerine ayırın. .../telemetry/..., .../state/... ve .../cmd/... dallarıyla bir cihaz acme/berlin/hall2/pump-3/cmd/# filtresine abone olup yalnızca komutları alabilir; bir analitik servisi ise kontrol trafiğini hiç görmeden yalnızca telemetriyi alabilir.
Tek bir seviyeye birden fazla bilgi kodlamayın. berlin-hall2-pump3 gibi bir seviye wildcard'larla bölünemez; berlin/hall2/pump3 bölünebilir.
Wildcard'lar ve Broker Yükü
Filtreleri topic'lerle eşleştirmek broker'ın gündelik işidir ve iyi tasarlanmış broker'lar wildcard'ları verimli şekilde işler. Kontrol edebildiğiniz maliyet dağıtım genişliğidir (fan-out): geniş bir filtre, istemcinize teslim edilen daha fazla mesaj, daha fazla bant genişliği ve daha fazla işlem anlamına gelir. Ölçülen veya kotayla sınırlı planlarda dar bir filtre aynı zamanda daha ucuz filtredir. Bir backend'in geniş bir dalı işlemesi gerektiğinde, aynı abonelikleri çoğaltmak yerine tüketici gruplarıyla ölçeklendirin.
MQTT Wildcard'larıyla İlgili Yaygın Hatalar
- Üretimde
#filtresine abone olmak. Broker'daki (veya kiracıdaki) her mesajı alır, bant genişliği tüketir ve plan kotalarına takılabilir. İşe yarayan en dar filtreyi kullanın. +'nın birden fazla seviyeyle eşleşmesini beklemek.home/+/temperature,home/kitchen/sensor1/temperatureile eşleşmez. İkinci bir+kullanın veya topic'leri yeniden yapılandırın.#'i ortaya koymak.home/#/temperaturegeçersizdir ve abonelik reddedilir.- Filtrelerin büyük/küçük harfe duyarlı olduğunu unutmak.
home/+/Temperature, küçük harfli topic'lerle eşleşmez. - Çakışan abonelikler. Çakışmalar farklı QoS seviyelerinde yinelenen teslimatlara yol açabilir.
- Sınırlara takılmak. Herkese açık broker istemci başına 10 aboneliğe ve 8 topic seviyesine izin verir; bu yüzden çok sayıda tam abonelik yerine iyi yerleştirilmiş tek bir wildcard'ı tercih edin.
Bir Wildcard Aboneliği Hiçbir Şey Almadığında
Şu kontrolleri sırayla yapın: SUBACK reason code'unun reddedilmiş bir filtre yerine başarı gösterdiğini doğrulayın; publisher'ın kullandığı tam topic'i yazdırın ve büyük/küçük harf ile baştaki eğik çizgi dahil seviye seviye filtrenizle karşılaştırın; gerçekte neyin publish edildiğini görmek için geçici olarak üst dala # ile abone olun; son olarak publisher ile subscriber'ın aynı broker'a ve kiracıya bağlı olduğunu kontrol edin. "Wildcard'lar bozuk" raporlarının çoğu, fazladan bir seviye veya bir büyük harf olarak ortaya çıkar.
Wildcard'lar MQTT paylaşımlı abonelikleriyle de birleşir: $share/workers/factory/+/telemetry/# gibi bir filtre, bütün bir dalı bir tüketici grubuna dağıtır. Önce protokolün temellerini istiyorsanız MQTT eğitimini okuyun.
Topic'leri ConnectMQ ile Keşfedin
ConnectMQ, portalında canlı bir topic gezgini ve tarayıcı içi MQTT istemcisi bulunan bir bulut MQTT broker'dır; böylece araç kurmadan wildcard filtrelerini gerçek topic ağacınıza karşı test edebilirsiniz. Kredi kartı gerektirmeden ücretsiz bir Serverless broker oluşturun, ardından cihazlarınızı TCP, TLS veya WebSocket üzerinden YOUR_USERNAME, YOUR_PASSWORD ve YOUR_CLIENT_ID ile bağlayın.
Sık Sorulan Sorular
MQTT'de + ile # arasındaki fark nedir?
+ tam olarak bir topic seviyesiyle eşleşir ve filtrenin herhangi bir yerinde bulunabilir. # sıfır veya daha fazla seviyeyle eşleşir ve filtrenin son karakteri olmalıdır.
Wildcard içeren bir topic'e publish edebilir miyim?
Hayır. Wildcard'lara yalnızca abonelik filtrelerinde izin verilir. + veya # içeren bir topic'e publish etmek protokol ihlalidir.
# filtresi $SYS topic'leriyle eşleşir mi?
Hayır. Bir wildcard ile başlayan filtreler $ ile başlayan topic'lerle eşleşmez. Bunları almak için açıkça $SYS/# filtresine abone olun.
home/# filtresi home topic'iyle eşleşir mi?
Evet. Çok seviyeli wildcard üst seviyeyle de eşleşir; dolayısıyla home/#, altındaki her şeyin yanı sıra home'a publish edilen mesajları da alır.



