ITcoDe.Uz ← Maqolalar

MQTT

MQTT'da duplicate client ID: qurilma nega har 30 soniyada uziladi

Signal kuchli, tarmoq barqaror, kod toza — lekin qurilma muntazam uzilib turadi. Bu xatoni topishga bir necha kun ketgan edi va sabab kodning eng ko'rinmas joyida edi.

Bakhrullo Nasrulloyev2026-08-14~6 daqiqa

Belgilar

NBcaR loyihasi ishga tushgach, seriya monitorda quyidagi manzara paydo bo'ldi:

MQTT connected
... 28 soniya jimlik ...
MQTT disconnected, rc=-3
Reconnecting...
MQTT connected
... 31 soniya jimlik ...
MQTT disconnected, rc=-3

Birinchi taxminlar mantiqiy edi va hammasi noto'g'ri chiqdi: GSM signali zaif emas edi, keep-alive vaqti to'g'ri sozlangan edi, brokerda limit tugamagan edi, quvvat ham yetarli edi.

Haqiqiy sabab

MQTT protokolida har bir mijoz brokerga noyob client ID bilan ulanishi shart. Bu identifikator sessiyani belgilaydi.

Agar ikkinchi mijoz xuddi shu ID bilan ulansa, broker buni "bir xil qurilma qayta ulanyapti" deb tushunadi va eskisini majburan uzadi. Bu xato emas, protokolning belgilangan xatti-harakati.

Mening kodimda esa shunday yozilgan edi:

// qurilmada
client.connect("nbcar", user, pass);

// telefondagi PWA da
mqtt.connect({ clientId: "nbcar", ... });

Ikkalasi ham nbcar. Natijada telefon ulanganda qurilma uzilardi, qurilma qayta ulanganda telefon uzilardi. Ular navbat bilan bir-birini quvib chiqarardi va bu abadiy davom etardi.

Nima uchun aynan 30 soniya? Bu tasodif emas edi. PWA da avtomatik qayta ulanish intervali 30 soniyaga sozlangan edi. Ya'ni tsikl davri kodning o'zidan kelib chiqqan.

Yechim

Har bir mijozga o'z ID sini berish kerak. Lekin oddiy "nbcar-device" va "nbcar-app" ham yetarli emas — agar foydalanuvchi ikki telefondan kirsa, muammo qaytadi.

To'g'ri yo'l: barqaror qism va tasodifiy qismni birlashtirish.

// qurilmada — MAC manzil noyob va o'zgarmas
String cid = "nbcar-dev-" + String((uint32_t)ESP.getEfuseMac(), HEX);
client.connect(cid.c_str(), user, pass);
// PWA da — har sessiya uchun tasodifiy quyruq
const cid = 'nbcar-app-' +
  Math.random().toString(16).slice(2, 10);

Qurilma uchun MAC manzil ideal: u har platada boshqacha va qayta yuklanganda o'zgarmaydi. Ilova uchun esa tasodifiy qism to'g'ri — chunki bir foydalanuvchi bir nechta qurilmadan kirishi mumkin.

Qanday tekshirish mumkin

Agar shunga o'xshash muammoga duch kelsangiz, quyidagilarni ketma-ket tekshiring:

  1. Uzilish davri barqarormi? Agar ha — bu tarmoq muammosi emas. Tarmoq nosozligi tasodifiy vaqtlarda bo'ladi, aniq interval bilan emas.
  2. Ikkinchi mijozni o'chiring. Telefondagi ilovani yoping va qurilmani kuzating. Agar uzilish to'xtasa — sabab topildi.
  3. Broker jurnaliga qarang. EMQX va Mosquitto da odatda "client ... kicked" yoki "takenover" degan yozuv chiqadi.
  4. Kodda client ID ni qidiring. Ko'pincha u qattiq yozilgan bo'ladi va namunadan ko'chirilgan bo'ladi.

Nima uchun bu tez-tez uchraydi

Internetdagi ko'pchilik namunada client ID oddiy satr sifatida yoziladi — "ESP32Client" yoki "mqttClient". Bitta qurilma bilan sinab ko'rganingizda hammasi ishlaydi va muammo ko'rinmaydi.

U faqat ikkinchi mijoz qo'shilganda paydo bo'ladi. Aynan shu paytda esa siz allaqachon boshqa qismlarni yozib bo'lgan bo'lasiz va xatoni yaqinda yozilgan koddan qidirasiz.

Qo'shimcha: clean session

Client ID ni tuzatgandan keyin yana bir jihatga e'tibor bering. MQTT da cleanSession bayrog'i bor:

Avtomobil boshqaruvi uchun men true ni tanladim. Sabab: uzilish paytida yuborilgan eski buyruq qayta ulangandan keyin bajarilib ketishini istamayman. "O't oldir" buyrug'i besh daqiqa kechikib kelsa, bu kutilmagan natija beradi.

Xulosa

Client ID — kichik detal, lekin u butun tizimning barqarorligini belgilaydi. Qoida oddiy: har bir ulanuvchi uchun alohida va noyob ID.

Bu xato ayniqsa achchiq, chunki u kodda emas, konfiguratsiyada yashiringan va debug jarayonida ko'zga tashlanmaydi. Endi men har qanday MQTT loyihasini aynan shu joyni tekshirishdan boshlayman.

MQTTEMQXESP32DebugIoT