publish() false döndürüyorsa veya gelen mesajlar callback'inize hiç ulaşmıyorsa en olası neden PubSubClient buffer boyutudur. Kütüphanenin varsayılan paket buffer'ı yalnızca 256 bayttır ve bundan büyük her şey hata mesajı vermeden başarısız olur. Bu rehber buffer'ın tam olarak neyi tutması gerektiğini, setBufferSize() ile nasıl boyutlandırılacağını ve büyük JSON payload'larını hiç büyük buffer ayırmadan nasıl akıtacağınızı açıklar.
Belirtiler
Buffer sorunları kafa karıştırıcıdır, çünkü hiçbir şey çökmez ve bağlantı açık kalır. Şu işaretlere dikkat edin:
mqtt.publish()bazı mesajlar içinfalsedöndürür, diğerleri için döndürmez; genellikle uzun olanlar için.- Küçük test mesajları callback'inize ulaşır, ancak backend'inizden gelen gerçek JSON asla ulaşmaz.
- JSON belgenize bir alan daha eklemek telemetriyi aniden durdurur.
- Bir topic'teki retained yapılandırma mesajları diğer client'larda görünür ama cihaza hiç ulaşmaz.
Bunların hepsi tek bir kuralla açıklanır: yalnızca payload değil, MQTT paketinin tamamı PubSubClient'ın dahili buffer'ına sığmalıdır.
Buffer Neyi Tutmalı?
PubSubClient hem giden hem de gelen paketler için tek bir buffer kullanır. Bir PUBLISH paketi için bu buffer şunları tutar:
| Bölüm | Boyut |
|---|---|
| Sabit başlık (paket türü ve bayraklar) | 1 bayt |
| Kalan uzunluk alanı | 1 ila 4 bayt (16 KB'a kadar olan çoğu mesaj için 2 bayt) |
| Topic uzunluk öneki | 2 bayt |
| Topic string'i | Topic'inizin uzunluğu |
| Paket tanımlayıcı | 2 bayt, yalnızca gelen QoS 1 mesajlar için |
| Payload | Mesajınızın uzunluğu |
Kütüphane paketi oluştururken birkaç baytlık başlık alanı ayırır; bu yüzden pratikte topic uzunluğu + payload uzunluğu + yaklaşık 7 bayt, gelen QoS 1 mesajlar için de 2 bayt daha gerekir. 256 baytlık varsayılan ve connectmq/demo/sensor-4d2a/telemetry (36 karakter) gibi bir topic ile payload'unuz kabaca 210 baytın altında kalmalıdır. On okuma ve zaman damgası içeren bir JSON belgesi bunu kolayca aşar.
Aynı limit, kütüphanenin buffer içinde oluşturduğu CONNECT (client ID, kimlik bilgileri ve will mesajı) ve SUBSCRIBE gibi diğer paketler için de geçerlidir. Çok uzun bir parola ile uzun bir will mesajı, CONNECT paketini bile 256 baytın üzerine çıkarabilir; bu da başarısız bir connect() olarak görünür.
Çözüm 1: setBufferSize() ile Buffer'ı Büyütün
PubSubClient 2.8'den itibaren buffer'ı çalışma zamanında yeniden boyutlandırabilirsiniz. Eski eğitimler PubSubClient.h içindeki MQTT_MAX_PACKET_SIZE değerini düzenlemenizi söyler; bu hâlâ çalışır ama kırılgandır, çünkü kütüphane güncellemeleri dosyanın üzerine yazar ve değişiklik sessizce kaybolur.
#include <WiFi.h>
#include <PubSubClient.h>
WiFiClient net;
PubSubClient mqtt(net);
void setup() {
Serial.begin(115200);
// ... Wi-Fi'ye bağlanın ...
mqtt.setServer("broker.connectmq.com", 1883);
if (!mqtt.setBufferSize(2048)) {
Serial.println("Could not allocate MQTT buffer");
}
Serial.printf("MQTT buffer size: %u\n", mqtt.getBufferSize());
}
Önemli noktalar:
setBufferSize()biruint16_talır, bu yüzden teorik üst sınır 65.535 bayttır.- Belleği yeniden ayırır ve ayırma başarısız olursa önceki buffer'ı yerinde bırakarak
falsedöndürür. Dönüş değerini her zaman kontrol edin. connect()öncesinde çağırın. Bağlıyken yeniden boyutlandırmak çalışır ama israftır.getBufferSize()mevcut boyutu doğrular.
Ne kadar büyük olmalı? Beklediğiniz en büyük mesaj için yukarıdaki formülü kullanın, ardından yüzde 10 ila 20 pay ekleyin. ESP8266'da "ne olur ne olmaz" diye 16 KB ayarlamayın: o RAM bu durumda TLS için kullanılamaz ve bir sonraki el sıkışma başarısız olabilir. ESP32'de birkaç kilobayt sorun değildir.
Çözüm 2: beginPublish() ile Büyük Payload'ları Akıtın
Buffer'ı büyütmek ara sıra gelen büyük mesajlar için uygundur, ancak akış (streaming) RAM maliyetini tamamen ortadan kaldırır. beginPublish() başlığı ve topic'i yazar, ardından payload'u parçalar halinde doğrudan ağ client'ına yazmanıza izin verir. Buffer'dan yalnızca başlık geçer; böylece 256 baytlık bir buffer kilobaytlarca büyüklükte bir payload gönderebilir.
Tek şart: MQTT payload uzunluğunu başlığa koyduğu için onu önceden bilmeniz gerekir. ArduinoJson bunu measureJson() ile kolaylaştırır.
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
const char* TOPIC = "connectmq/demo/sensor-4d2a/batch";
WiFiClient net;
PubSubClient mqtt(net);
bool publishBatch(const float* values, size_t count) {
JsonDocument doc; // ArduinoJson 7
doc["device"] = "sensor-4d2a";
doc["uptime"] = millis() / 1000;
JsonArray arr = doc["values"].to<JsonArray>();
for (size_t i = 0; i < count; i++) arr.add(values[i]);
size_t len = measureJson(doc);
if (!mqtt.beginPublish(TOPIC, len, false)) {
Serial.println("beginPublish failed");
return false;
}
serializeJson(doc, mqtt); // PubSubClient bir Print olduğu için bu akış halinde yazar
return mqtt.endPublish() == 1;
}
200 float değerle payload 256 bayttan çok daha büyüktür, ancak varsayılan buffer yeterlidir. beginPublish(), write()/print() ve endPublish() PubSubClient 2.7 ve sonrasında mevcuttur.
Broker'ın yine tek bir MQTT mesajı gördüğünü ve bu mesajın broker limitinin içinde olması gerektiğini unutmayın. broker.connectmq.com adresindeki herkese açık MQTT test broker'ında limit mesaj başına 64 KB'tır.
Büyük Mesajları Almak
Akış yalnızca giden mesajlarda işe yarar. Gelen mesajlarda PubSubClient, callback'inizi çağırmadan önce paketin tamamını buffer'a okur. Paket buffer'dan büyükse kütüphane onu okur ve atar; callback'iniz hiç çağrılmaz. Hata da yoktur, log da.
Bu nedenle büyük yapılandırma belgeleri veya firmware manifestoları alan cihazlar için:
- Buffer'ı en büyük gelen mesaj artı topic artı ek yük kadar ayarlayın.
- Gelen mesajları kompakt tutun. Tam bir backend nesnesi yerine yalnızca cihazın ihtiyaç duyduğu alanları gönderin.
- Büyük verileri, her biri limitin rahatça altında kalacak şekilde birkaç topic'e bölün; örneğin
config/networkveconfig/sensors. - Firmware imajları gibi gerçekten büyük payload'lar için MQTT üzerinden bir URL yayınlayın ve dosyayı HTTPS üzerinden indirin.
Bilerek fazla büyük bir mesajla ne olduğunu test edin:
mosquitto_pub -h broker.connectmq.com -p 1883 -i sizetest-4d2a \
-t "connectmq/demo/sensor-4d2a/cmd" \
-m "$(head -c 400 /dev/zero | tr '\0' 'x')"
Varsayılan buffer ile cihaz bunu yok sayar. setBufferSize(1024) sonrasında callback 400 uzunluğuyla tetiklenir.
Hata Ayıklama Kontrol Listesi
Mesajlar kaybolduğunda bu listeyi izleyin:
- Ayarladığınızı düşündüğünüz boyutu doğrulamak için kurulumdan sonra
mqtt.getBufferSize()yazdırın. - Her yayından önce topic ve payload uzunluğunu loglayın:
Serial.printf("%u + %u\n", strlen(topic), strlen(payload));. publish()dönüş değerini kontrol edin ve başarısız olduğunda boyut sorunlarını bağlantı sorunlarından ayırmak içinmqtt.connected()yazdırın.- ESP8266'da
ESP.getMaxFreeBlockSize()değerini izleyin. Büyük bir buffer ile TLS birlikte bitişik belleği tüketebilir. - Bir masaüstü client'ıyla karşılaştırın:
mosquitto_submesajı alıyor ama cihaz almıyorsa buffer çok küçüktür. - Mesajınızın cihaz buffer'ının yanı sıra broker'ınızın limiti içinde de olduğundan emin olun.
Bağlantının kendisi başarısız oluyorsa neden başka yerdedir; bkz. PubSubClient rc=-2 ve diğer durum kodları. Kütüphanenin eksiksiz anlatımı için PubSubClient eğitimimizi okuyun. Gelen mesajları da akış halinde işleyen bir kütüphaneye ihtiyacınız varsa ArduinoMqttClient rehberi alternatif bir yaklaşım gösterir; ESP32 IoT eğitimi ise bu teknikleri eksiksiz bir projede birleştirir.
Broker Mesaj Limitleri
Cihaz buffer'ı işin yalnızca yarısıdır. Her broker mesaj boyutunu da sınırlar ve limitin üzerindeki mesajlar reddedilir veya bağlantının kopmasına neden olur:
| Ortam | Maksimum mesaj boyutu |
|---|---|
| ConnectMQ herkese açık broker (broker.connectmq.com) | 64 KB |
| ConnectMQ Serverless (Free) | 256 KB |
| ConnectMQ Serverless (Paid) | 1 MB |
Gömülü cihazlar için düşük kilobaytlarda kalmak zaten iyi bir uygulamadır. Daha küçük mesajlar daha az RAM, daha hızlı TLS kayıtları ve zayıf Wi-Fi'de daha az yeniden iletim demektir.
ConnectMQ ile Daha Büyük Payload'lar Gönderin
Telemetriniz herkese açık broker'ı aştıysa yönetilen bir MQTT broker size özel kimlik bilgileri, TLS ve daha yüksek mesaj limitleri sağlar. ConnectMQ; MQTT 3.1.1 ve 5.0, tarayıcı içi bir MQTT client'ı ve cihazlarınızın tam olarak ne gönderdiğini inceleyebileceğiniz canlı bir topic gezgini sunan bir bulut MQTT broker'dır. app.connectmq.com adresinde ücretsiz bir Serverless broker oluşturun, kredi kartı gerekmez.
Sık Sorulan Sorular
Varsayılan PubSubClient buffer boyutu nedir?
MQTT_MAX_PACKET_SIZE olarak tanımlanan 256 bayt. Topic ve başlıklar dahil paketin tamamını kapsar, bu yüzden kullanılabilir payload daha küçüktür.
MQTT_MAX_PACKET_SIZE'ı mı düzenlemeliyim, yoksa setBufferSize() mı kullanmalıyım?
PubSubClient 2.8 veya sonrasında setBufferSize() kullanın. Kütüphane güncellemelerinden etkilenmez ve bellek ayırmanın başarılı olup olmadığını kontrol etmenizi sağlar.
publish() büyük bir mesajda neden false döndürüyor?
Topic, payload ve başlık toplamı buffer'ı aşıyor. Buffer'ı büyütün veya payload'u akıtmak için beginPublish() kullanın.
PubSubClient buffer'ından büyük mesajları alabilir mi?
Hayır. Aşırı büyük gelen mesajlar callback'iniz çalışmadan önce atılır. Buffer'ı büyütün veya gelen mesajları küçük tutun.



