Seri monitörde failed, rc=-2 görmek en yaygın PubSubClient hatasıdır ve bu mesaj tek başına size çok az şey söyler. PubSubClient rc=-2, broker'a giden TCP (veya TLS) bağlantısının hiç açılamadığı anlamına gelir; dolayısıyla sorun neredeyse her zaman MQTT'nin kendisinde değil, DNS'te, portta, ağda veya sertifikadadır. Bu rehber -4 ile 5 arasındaki her durum kodunu çözümler ve her biri için bir çözüm sunar.
rc Değeri Nereden Gelir?
PubSubClient son bağlantı denemesinin sonucunu, mqtt.state() ile okuduğunuz dahili bir durum değişkeninde saklar. Örnek sketch'lerin çoğu, connect() false döndürdüğünde bu değeri yazdırır:
if (!mqtt.connect(clientId)) {
Serial.print("failed, rc=");
Serial.println(mqtt.state());
}
Değerler PubSubClient.h içinde sabit olarak tanımlanmıştır. Negatif değerler kütüphaneden ve ağ katmanından gelir. Pozitif değerler ise broker'ın CONNACK paketinde geri gönderdiği, MQTT 3.1.1 spesifikasyonunda tanımlanan dönüş kodlarıdır.
| rc | Sabit | Katman | Sade anlamı |
|---|---|---|---|
| -4 | MQTT_CONNECTION_TIMEOUT |
Kütüphane | Soket açıldı ama zamanında CONNACK (veya ping yanıtı) gelmedi |
| -3 | MQTT_CONNECTION_LOST |
Ağ | Kurulmuş bir bağlantı koptu |
| -2 | MQTT_CONNECT_FAILED |
Ağ | Soket hiç açılamadı |
| -1 | MQTT_DISCONNECTED |
Kütüphane | Client düzgün şekilde bağlantıyı kesti |
| 0 | MQTT_CONNECTED |
Broker | Bağlı |
| 1 | MQTT_CONNECT_BAD_PROTOCOL |
Broker | Protokol sürümü kabul edilmedi |
| 2 | MQTT_CONNECT_BAD_CLIENT_ID |
Broker | Client ID reddedildi |
| 3 | MQTT_CONNECT_UNAVAILABLE |
Broker | Broker şu anda bağlantı kabul edemiyor |
| 4 | MQTT_CONNECT_BAD_CREDENTIALS |
Broker | Kullanıcı adı veya parola yanlış |
| 5 | MQTT_CONNECT_UNAUTHORIZED |
Broker | Bağlanma yetkisi yok |
Asıl önemli nokta şu: negatif kodlarda broker sizi ya hiç görmedi ya da hiç yanıt vermedi. Pozitif kodlarda ise broker CONNECT paketinizi aldı ve bilinçli olarak reddetti.
PubSubClient rc=-2 Hatasını Çözmek
rc=-2, alttaki ağ nesnesinde client.connect(host, port) her başarısız olduğunda raporlandığı için pek çok olası nedeni vardır. Bunları şu sırayla kontrol edin.
1. Wi-Fi Aslında Bağlı Değil
WiFi.status() == WL_CONNECTED olmadan önce mqtt.connect() çağırmak her zaman -2 döndürür. Bu durum, erişim noktası bağlantınızı düşürdüğünde ve döngünüz yalnızca MQTT'yi kontrol ettiğinde de yaşanır. Her döngüde önce Wi-Fi'yi kontrol edin ve MQTT'ye dokunmadan önce Wi-Fi'yi yeniden bağlayın.
2. DNS Başarısız veya Host Adı Yanlış
Sonunda boşluk bulunan broker.connectmq.com gibi yazım hataları, mqtt://broker.connectmq.com (host adı yerine URL) veya http:// önekleri sessizce başarısız olur. setServer() yalın bir host adı veya bir IPAddress bekler. DNS'i doğrudan test edin:
IPAddress ip;
if (WiFi.hostByName("broker.connectmq.com", ip)) {
Serial.print("Resolved to ");
Serial.println(ip);
} else {
Serial.println("DNS lookup failed");
}
DNS başarısız olursa DHCP'nin size bir DNS sunucusu verip vermediğini kontrol edin veya WiFi.config() ile açıkça bir DNS sunucusu ayarlayın.
3. Client Türü İçin Yanlış Port
Bu klasik hatadır. Port ile ağ client'ı birbirine uymalıdır:
| Port | Taşıma | Kullanılacak Arduino client'ı |
|---|---|---|
| 1883 | TCP üzerinden düz MQTT | WiFiClient |
| 8883 | TLS üzerinden MQTT | WiFiClientSecure |
| 8083 / 8084 | WebSocket üzerinden MQTT | PubSubClient tarafından desteklenmez |
8883'e yönlendirilmiş bir WiFiClient bir TCP soketi açar, ardından broker TLS el sıkışması beklediği için takılır veya başarısız olur; bu çoğu zaman -2 veya -4 olarak görünür. 1883'e yönlendirilmiş bir WiFiClientSecure ise el sıkışmada başarısız olur ve -2 döndürür. PubSubClient WebSocket konuşamaz; bu yüzden 8083 ve 8084 portları tarayıcılar ve WebSocket üzerinden MQTT yazısında anlatılan araçlar içindir.
4. TLS Sertifika Sorunları
WiFiClientSecure ile başarısız bir sertifika doğrulaması da rc=-2 olarak raporlanır. Yaygın nedenler:
- CA sertifikası ayarlanmamış. ESP32'de, broker sertifikasını imzalayan kök sertifikayla
setCACert()çağırın. ConnectMQ Let's Encrypt kullanır, dolayısıyla kök sertifika ISRG Root X1'dir. - O tarihten bu yana yenilenmiş bir yaprak (leaf) veya ara sertifikayı sabitlemek (pinning). Let's Encrypt sertifikalarının ömrü kısadır; yaprağı değil kökü sabitleyin.
- ESP8266'da yanlış sistem saati. BearSSL geçerlilik tarihlerini kontrol eder, bu nedenle bağlanmadan önce saati
configTime()ile senkronize edin. - Yetersiz bellek. TLS el sıkışması heap'ten azımsanmayacak bir pay ister; ESP8266'da büyük bir MQTT buffer'ı ile TLS birlikte belleği tüketebilir.
ESP32'de başarısız bir denemeden sonra alttaki TLS hatasını yazdırabilirsiniz:
char err[128];
int code = netClient.lastError(err, sizeof(err));
Serial.printf("TLS error %d: %s\n", code, err);
Sorunu izole etmek için geçici olarak netClient.setInsecure() çağırın. Böyle bağlanıyorsa sorun sertifika yapılandırmanızdadır. setInsecure() içeren bir firmware'i asla yayına almayın.
5. Ağ Giden MQTT Trafiğini Engelliyor
Kurumsal, okul ve bazı misafir ağları giden 1883 ve 8883 portlarını engeller. Aynı sketch'i bir telefon hotspot'unda deneyin. Orada çalışıyorsa portun açılmasını isteyin veya cihazı farklı bir ağ segmentine taşıyın.
6. Çok Sık Bağlanmaya Çalışmak
Broker IP adresinizden tekrar tekrar başarısız denemeler görürse bağlantıları geçici olarak reddedebilir. Örneğin ConnectMQ, tenant'ları korumak için tekrarlanan başarısız girişlerden sonra IP adreslerini engeller. Gecikmesiz bir yeniden bağlanma döngüsü, tek bir yanlış parolayı rc=-2 gibi görünen bir kilitlenmeye dönüştürebilir. Denemeler arasında her zaman en az birkaç saniye bekleyin ve birkaç başarısızlıktan sonra bekleme süresini daha da artırın.
rc=-4 (Bağlantı Zaman Aşımı) Hatasını Çözmek
Burada soket açılmıştır ama CONNACK, soket zaman aşımı süresi (varsayılan olarak 15 saniye) içinde gelmemiştir. Tipik nedenler:
- Yukarıda anlatıldığı gibi, TLS portunda düz
WiFiClientkullanmak. - Yoğun paket kaybı olan zayıf Wi-Fi sinyali.
WiFi.RSSI()değerini yazdırın; -80 dBm civarı veya daha zayıf her değer güvenilmezdir. - Engelleyici (blocking) kod. Bağlantı daha önce kurulduysa, keep alive ping'lerinin yanıtlanması için
loop()yeterince sık çağrılmadığında -4 daha sonra da ortaya çıkabilir.
rc=-3 (Bağlantı Koptu) Hatasını Çözmek
Bağlantı çalıştı, sonra koptu. Şunlara bakın:
- Yinelenen client ID'ler. İkinci bir cihaz aynı ID ile bağlandığında broker ilkini düşürür. Aynı sketch ile yüklenmiş iki kart sırayla birbirini dışarı atar. ID'leri MAC adresinden üretin.
- Keep alive süresinin dolması. Uzun
delay()çağrıları veya yavaş sensör okumalarımqtt.loop()çağrısını aç bırakır. - Aşırı büyük veya çok sık mesajlar. Broker'lar limit uygular. broker.connectmq.com adresindeki herkese açık MQTT test broker'ında client'lar mesaj başına 64 KB ve saniyede 10 mesajla sınırlıdır; limitlerin aşılması oturumun kapanmasına yol açabilir.
Pozitif Kodları (1 ile 5 Arası) Çözmek
rc=1: Hatalı Protokol
PubSubClient varsayılan olarak MQTT 3.1.1 gönderir. Bu kodu yalnızca MQTT_VERSION değerini 3.1 olarak derleyip bunu reddeden bir broker'a bağlandıysanız görürsünüz. Bu ayarı kaldırın.
rc=2: Client ID Reddedildi
Genellikle suçlu boş bir client ID'dir. ConnectMQ herkese açık broker'ı, anonim bağlantılarda bile boş olmayan bir client ID gerektirir. Özel bir ConnectMQ broker'ında client ID'ler portalda verilen kimlik bilgilerine bağlıdır; bu yüzden size verilen client ID'yi birebir kullanın.
rc=3: Sunucu Kullanılamıyor
Broker çalışıyor ama bağlantı kabul etmiyor; örneğin bakım sırasında veya bir bağlantı kotasına ulaşıldığında. Bekleyip yeniden deneyin. Kendi broker'ınızda devam ediyorsa planınızın bağlantı limitini aşıp aşmadığınızı kontrol edin.
rc=4: Hatalı Kullanıcı Adı veya Parola
Kimlik bilgilerini portaldan yeniden kopyalayın ve görünmez karakterlere dikkat edin. connect(id, user, pass) fonksiyonunun önce client ID aldığını unutmayın; sıranın karıştırılması şaşırtıcı derecede yaygındır.
rc=5: Yetkisiz
Broker kimlik bilgilerini anladı ama bu client'ı reddediyor; örneğin kullanıcı adı ile client ID birbirine ait olmadığı için. Üç değeri de yeniden kontrol edin.
Tanılama Amaçlı Bir Connect Fonksiyonu
Çıplak bir sayı yerine okunabilir bir neden almak için bunu herhangi bir sketch'e ekleyin:
const char* mqttStateText(int s) {
switch (s) {
case -4: return "timeout (no CONNACK) - check port/TLS match and signal";
case -3: return "connection lost - duplicate client ID or keep alive";
case -2: return "socket failed - Wi-Fi, DNS, port, firewall or TLS cert";
case -1: return "disconnected";
case 0: return "connected";
case 1: return "bad protocol version";
case 2: return "client ID rejected - empty or not allowed";
case 3: return "server unavailable - retry later";
case 4: return "bad username or password";
case 5: return "not authorised";
default: return "unknown";
}
}
bool connectWithDiagnostics() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Wi-Fi not connected, skipping MQTT");
return false;
}
if (mqtt.connect(DEVICE_ID)) {
Serial.println("MQTT connected");
return true;
}
int s = mqtt.state();
Serial.printf("MQTT failed rc=%d: %s\n", s, mqttStateText(s));
return false;
}
Hızlı İzolasyon Kontrol Listesi
- Bilgisayarınız broker'a ulaşabiliyor mu?
mosquitto_sub -h broker.connectmq.com -p 1883 -i test-$RANDOM -t "connectmq/demo/check/#" -vkomutunu çalıştırın. Bu başarısız olursa sorun kartta değil, ağınızdadır. - Kart host adını çözümleyebiliyor mu? Yukarıdaki DNS kod parçasını kullanın.
WiFiClientve anonim, benzersiz bir client ID ile 1883'te bağlanıyor mu? Evetse sorun TLS'te veya kimlik bilgilerindedir.setInsecure()ile 8883'te bağlanıyor mu? Evetse CA sertifikasını düzeltin.- CA ile bağlanıyor ama kimlik bilgileriyle başarısız mı oluyor? Kullanıcı adını, parolayı ve client ID'yi yeniden kontrol edin.
Bağlandıktan sonra insanların karşılaştığı bir sonraki sorun mesaj boyutudur; bkz. PubSubClient buffer boyutu. Kütüphanenin eksiksiz anlatımı için PubSubClient Arduino eğitimimizi, eksiksiz bir proje için ise ESP32 IoT eğitimi ana rehberini okuyun.
Yönetilen Bir Broker ile rc Kodlarının Peşinden Koşmayı Bırakın
rc=-2 ve rc=-4 hatalarının çoğu, süresi dolmuş sertifikalara, kapalı güvenlik duvarı portlarına veya çökmüş servislere sahip kendi barındırdığınız broker'lardan kaynaklanır. ConnectMQ gibi tam yönetilen bir MQTT servisi bu değişkenleri ortadan kaldırır: otomatik yenilenen Let's Encrypt sertifikasıyla 8883'te TLS, sizin için oluşturulan kimlik bilgileri ve portalda, cihazda hata ayıklamaya başlamadan önce broker tarafının çalıştığını doğrulayabilmeniz için bir tarayıcı MQTT client'ı. app.connectmq.com adresinde ücretsiz bir Serverless broker başlatın, kredi kartı gerekmez.
Sık Sorulan Sorular
PubSubClient'ta rc=-2 ne anlama gelir?
Broker'a ağ bağlantısının açılamadığı anlamına gelir. Broker CONNECT paketinizi hiç almadı; bu yüzden Wi-Fi'yi, DNS'i, portu ve TLS kullanıyorsanız CA sertifikasını kontrol edin.
Neden yalnızca 8883 portunda rc=-2 alıyorum?
TLS kurulumunuz başarısız oluyor. WiFiClientSecure kullandığınızdan, doğru kök sertifikayı (Let's Encrypt kullanan broker'lar için ISRG Root X1) yüklediğinizden ve ESP8266'da bağlanmadan önce saati ayarladığınızdan emin olun.
Kartım bağlanıyor, sonra birkaç saniyede bir rc=-3 gösteriyor. Neden?
Çoğu zaman başka bir cihaz veya araç aynı client ID'yi kullanıyordur; bu yüzden broker bir oturumu sürekli diğeriyle değiştirir. Her cihaza, örneğin MAC adresine dayalı, benzersiz bir ID verin.
rc=5, rc=4'ten farklı mı?
Evet. rc=4 kullanıcı adının veya parolanın yanlış olduğu anlamına gelir. rc=5 ise kimlik bilgilerinin anlaşıldığı ama bu client'ın bağlanmasına izin verilmediği anlamına gelir; bunun nedeni çoğu zaman client ID'nin kimlik bilgileriyle eşleşmemesidir.



