Uygulamalı Eğitimler

MQTT ile Gerçek Zamanlı Sohbet Uygulaması Geliştirin

MQTT üzerinde tarayıcı sohbeti geliştirin: topic olarak odalar, retained mesaj ve Last Will ile çevrimiçi durumu, ACL ile korunan gönderen kimliği; hepsi tek HTML dosyasında.

Güncellendi · 9 dk okuma

MQTT ile Gerçek Zamanlı Sohbet Uygulaması Geliştirin

MQTT, bir sohbet uygulamasının en zor kısmını zaten halleder: Her mesajı gerçek zamanlı olarak tüm subscriber'lara iletir. MQTT üzerinde bir sohbet uygulaması üç karara indirgenir: Odaların topic'lere nasıl eşleneceği, çevrimiçi durumun (presence) nasıl çalışacağı ve birinin başkasının adıyla mesaj göndermesinin nasıl engelleneceği. Bu rehber, MQTT.js ile tek bir HTML dosyasında, güvenli WebSocket üzerinden bağlanan, çalışan çok odalı bir sohbet geliştiriyor; ardından onu nasıl test edip sağlamlaştıracağınızı gösteriyor.

Topic tasarımı

TopicPayloadQoSRetainedAmaç
testmqtt/chat/<room>/messages/<user>{"text":"…","ts":…}1HayırSohbet mesajları
testmqtt/chat/<room>/presence/<user>{"status":"online"} veya {"status":"offline"}1EvetOdada kimlerin olduğu

Bu yapıdaki iki tercih işin çoğunu görür:

  • Gönderen, topic'in bir parçasıdır. Bir istemci testmqtt/chat/<room>/messages/+ topic'ine subscribe olur ve kullanıcı adını topic'in son seviyesinden okur. Her kullanıcının yalnızca kendi adı altında yazmasına izin veren bir ACL ile (aşağıda ele alınıyor) gönderen artık taklit edilemez. JSON içindeki bir "user" alanı ise taklit edilebilirdi.
  • Presence, kullanıcı başına bir retained mesajdır. Retained mesajlar bir istemci subscribe olduğu anda teslim edilir; böylece yeni gelen biri, kimseye sormadan üye listesinin tamamını hemen görür.

Odalar yalnızca <room> için farklı değerlerdir; bu yüzden broker'da hiçbir yapılandırma yapmadan istediğiniz kadar oda açabilirsiniz. Topic tasarımı en iyi uygulamaları, tanımlayıcısı sonda olan bunun gibi kararlı hiyerarşilerin neden iyi ölçeklendiğini açıklar.

Retained mesajlar ve Last Will ile presence

Presence, iki MQTT özelliğini birlikte kullanır:

  1. Bağlandıktan sonra istemci, kendi presence topic'ine {"status":"online"} mesajını retained olarak publish eder.
  2. Aynı istemci CONNECT paketinde aynı topic için yine retained bir Last Will kaydeder: {"status":"offline"}.

Bağlantı düzgün bir MQTT DISCONNECT olmadan biterse (sekme kapandı, dizüstü uykuya geçti, ağ gitti) broker will mesajını publish eder. Will retained olduğu için "online" mesajının yerini alır ve tüm üyeler kullanıcının çevrimdışı olduğunu görür. Kullanıcı Leave'e tıkladığında istemci, boş bir retained payload publish ederek presence kaydını bilinçli olarak temizler; bu, retained mesajı siler.

Sohbet sayfasının tamamı

Bunu chat.html olarak kaydedin ve iki kez açın: chat.html?user=alice ve chat.html?user=bob. Bir oda seçmek için &room=ekibiniz ekleyin. Paylaşımlı test endpoint'inde yabancılarla sohbet etmemek için alışılmadık bir oda adı seçin.

@@CHAT@@

Dikkat edilmesi gereken birkaç ayrıntı:

  • textContent, asla innerHTML değil. Sohbet mesajları diğer kullanıcılardan gelen güvenilmeyen girdilerdir. Onları HTML olarak işlemek bir cross-site scripting açığıdır.
  • Oda ve kullanıcı adları temizlenir; böylece /, + veya # içeren bir ad kendi topic seviyesinin dışına taşamaz.
  • Kendi mesajlarınız broker üzerinden geri gelir. Bu sizin teslimat onayınızdır. Onları yerelde göstermeyi tercih ederseniz MQTT 5, { qos: 1, nl: true } (No Local) ile subscribe olmanıza izin verir; böylece broker mesajları size geri göndermez.
  • Hatalı biçimlendirilmiş payload'lar handler'ı çökertmek yerine yok sayılır, çünkü publish izni olan herkes her şeyi gönderebilir.

MQTT.js kurulumu sizin için yeniyse, bağlantı seçeneklerini ve hata ayıklama akışını açıklayan tarayıcıda saf JavaScript ile MQTT yazısıyla başlayın.

Test edin

İki sekme açın (alice ve bob) ve şu kontrolleri yapın:

  1. Mesajlar iki yönde de akıyor. Her mesaj iki sekmede de görünür; gönderen topic'ten alınır.
  2. Sonradan gelenler presence'ı görüyor. Üçüncü bir sekme açın: Üye listesi retained mesajlarla hemen dolar.
  3. Will tetikleniyor. Bob'un sekmesini kapatın. Alice birkaç saniye içinde bob'u gri görmelidir.
  4. Leave temizliyor. Bir sekmede Leave'e tıklayın: Kullanıcı çevrimdışı görünmek yerine listeden kaybolur.

Ham trafiği görmek için online MQTT istemcisinde testmqtt/chat/lobby/# topic'ine subscribe olun veya terminalden şunu kullanın:

Bir odayı izleyin ve bot olarak mesaj gönderin
mosquitto_sub -h broker.connectmq.com -t 'testmqtt/chat/lobby/#' -v

mosquitto_pub -h broker.connectmq.com -q 1 \
  -t testmqtt/chat/lobby/messages/deploy-bot \
  -m "{\"text\":\"Build 412 deployed\",\"ts\":$(date +%s)000}"

İkinci komut, herhangi bir servisin (CI, izleme, bir backend) tek bir publish ile bir odaya mesaj gönderebileceğini gösterir. Will'i sınamanın başka yolları için Last Will testi yazısına bakın.

Lobby'yi online istemcide izleyin

Kimliği ACL'lerle zorunlu kılın

Açık bir test endpoint'inde herkes testmqtt/chat/lobby/messages/alice topic'ine publish edebilir. Production'da her kullanıcıya kendi broker kimlik bilgilerini ve topic'leri kullanıcı adına bağlayan bir ACL verin. Mosquitto'da pattern kuralları %u ifadesini kimliği doğrulanmış kullanıcı adıyla değiştirir:

acl_file (Mosquitto)
# Everyone can read every room
pattern read testmqtt/chat/+/#

# ...but may only write under their own name
pattern write testmqtt/chat/+/messages/%u
pattern write testmqtt/chat/+/presence/%u

Broker will mesajını da aynı kurallara göre denetler; yani bir istemci başkasının presence topic'ine will de kaydedemez. Ardından başka bir kullanıcının topic'ine yapılan publish'in gerçekten reddedildiğini ACL izin testleri ile doğrulayın. MQTT 3.1.1'de böyle bir publish genellikle sessizce düşürülür; bu yüzden bir hata beklemek yerine mesajın hiç ulaşmadığını kontrol edin.

MQTT'nin size vermedikleri

İhtiyaçYalnızca MQTTTipik çözüm
Mesaj geçmişi ve geriye kaydırmaHayır (topic başına yalnızca son retained mesaj)Veritabanına yazan bir backend subscriber'ı ve bir HTTP geçmiş endpoint'i
Saatlerce uzakta kalan kullanıcıya teslimatKalıcı session'lar mesajları kuyruğa alır, ama broker sınırları içindeVeritabanı ve yeniden bağlanınca "son görülmeden beri" sorgusu
Okundu bilgisi ve yazıyor göstergesiYerleşik değilEk topic'ler, örn. QoS 0 ile .../typing/<user>
Moderasyon, mesaj silmeHayırBir sistem topic'ine publish izni olan backend servisi

Kalıcı session'lar ayrıca session durumunu saklayan bir broker gerektirir. Paylaşımlı test endpoint'i bunu yapmaz; kaçırılan mesajları yakalama davranışını kendi instance'ınızda test edin.

MQTT üzerinde gerçek zamanlı bir sohbet büyük ölçüde topic tasarımıdır: Topic seviyesi olarak odalar, topic içinde gönderen, Last Will ile retained presence ve her kullanıcıyı kendi şeridinde tutan ACL'ler. Onu tek bir HTML dosyasında geliştirin, her davranışı iki sekme ve # izleyen bir subscriber ile kontrol edin; veritabanını yalnızca kullanıcıların geçmişe ihtiyaç duyduğunda ekleyin.

Sıkça sorulan sorular

MQTT sohbet için iyi bir protokol mü?

Canlı teslimat için evet: publish/subscribe odalarla doğal olarak örtüşür, mesajlar küçüktür ve Last Will çevrimiçi durumu bedavaya sağlar. Ancak MQTT sohbet geçmişini saklamaz; kullanıcıların geriye kaydırması veya çevrimdışı kaldıktan sonra kaçırdıklarını görmesi gerekiyorsa onu bir veritabanıyla birlikte kullanın.

MQTT ile kimin çevrimiçi olduğunu nasıl gösteririm?

Her istemci kendi presence topic'ine retained bir 'online' mesajı publish eder ve aynı topic'e retained bir 'offline' Last Will kaydeder. Yeni istemciler subscribe olduklarında tüm retained presence mesajlarını alır; bir istemci kaybolduğunda da broker will mesajını publish eder.

Kullanıcıların birbirinin kimliğine bürünmesini nasıl engellerim?

Gönderenin kullanıcı adını topic'e koyun, örneğin chat/<oda>/messages/<kullanıcı>, ve her kullanıcının yalnızca kendi adı altında publish etmesine izin veren bir broker ACL'i kullanın. Böylece alıcılar payload içindeki bir isim alanına değil, topic'e güvenir.