本文介紹設備端使用C Link SDK 3.x版本,通過MQTT協議連接物聯網平臺,可能出現的問題和解決方法。
物聯網平臺接入域名和端口號是什么?
接入域名:
新版公共實例和企業版實例的接入域名,請在物聯網平臺控制臺實例概覽頁面,單擊實例,進入實例詳情頁查看。
公共實例的接入域名:
${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com
。 其中:${YourProductKey}:請替換為設備所屬產品的ProductKey。可從物聯網平臺控制臺設備詳情頁獲取。
${YourRegionId}:請參見支持的地域,替換為您的Region ID。
端口號:1883。
詳細內容,請參見查看實例終端節點。
使用MQTT協議連接,不同的設備可以使用相同的clientID連接服務器嗎?
clientID需為全局內不重復。如果不同的設備使用相同的clientID同時連接物聯網平臺,那么先連接的那個設備會被強制斷開。
MQTT協議版本是多少?
在MQTT connect packet中設置MQTT的版本。目前SDK(V2.02)使用MQTT 3.1.1。
可以修改SDK代碼中src\mqtt\mqtt_client.h IOTX_MC_MQTT_VERSION
的值,來修改支持的版本,3表示3.1版,4表示3.1.1版。
MQTT進行設備認證時,server返回“400”錯誤
認證返回400錯誤,表示鑒權認證失敗。請檢查設備證書信息ProductKey、DeviceName和DeviceSecret是否正確。
C語言SDK中MQTT是否支持iOS接入?
C語言SDK可以移植到任何能夠支持C語言的系統上。如果是iOS系統建議尋找開源的Object-C實現。
目前mqtt-example設備上線后會立刻下線,如何修改mqtt-example讓設備一直處于上線狀態?
mqtt-example程序發送一次消息后會自動退出,可以嘗試以下任意一種方式實現一直在線。
執行mqtt-example時,使用命令行
./mqtt-example loop
,設備會保持一直在線。修改demo代碼。mqtt-example的代碼在最后會調用IOT_MQTT_Destroy,設備最后會變成離線狀態,所以可以修改代碼,去掉IOT_MQTT_Unregister 和IOT_MQTT_Destroy。
while(1) { IOT_MQTT_Yield(pclient, 200); HAL_SleepMs(100); }
心跳的時間間隔如何設置?
在IOT_MQTT_Construct里面可以設置keepalive_interval_ms的取值,物聯網平臺使用這個值來作為心跳間隔時間。keepalive_interval_ms的取值范圍是30~1200秒。
設備端的重連機制是什么?
設備端會在keepalive_interval_ms時間間隔發送ping request,然后等待ping response。
如果設備端在keepalive_interval_ms時間內無法收到ping response,或是在進行send以及recv時發生錯誤,平臺就認為此時網絡斷開,而需要進行重連。
重連機制是平臺內部觸發,無需使用者接入。重連時,會重新進行認證。如果認證成功就會開始再次進行MQTT connect。重連會一直持續直到再次連接成功。
物聯網平臺如何偵測到設備離線?
物聯網平臺會根據MQTT CONNECT packet里面keepalive的設置,等待ping request。如果在指定時間內沒有收到ping request,則認為設備離線。
物聯網平臺可以接受的最大時延是5秒。
設備端SDK是否支持MQTT和CCP協議的斷線重連?
支持。測試場景描述:開發板通過Wi-Fi連接上路由器后,把網線拔掉,MQTT和CCP協議都會自動嘗試和server重新建立連接。嘗試時間間隔是1s、2s、4s、8s、…,最大間隔時間默認是60s,也就是說斷網后超過60s時間仍未連接成功,之后會每隔60s嘗試和server重連。您可以設置最大間隔時間。
發布QoS1數據時,偶爾會出現MQTT_PUSH_TO_LIST_ERROR(-42),如何解決?
需要等待ACK的packet都會存放起來,等待ACK。存放量有上限,當需要等待的packet太多到達上限時,就會觸發MQTT_PUSH_TO_LIST_ERROR(-42) error
。
出現錯誤可能是因為當前網絡狀態不好,或者是發送的頻率過高。如果排除上述兩個問題,當前的發送的頻率是預期的,那么可以適當的調整IOTX_MC_REPUB_NUM_MAX、IOTX_MC_SUB_REQUEST_NUM_MAX和IOTX_MC_SUB_NUM_MAX的大小。
如果業務允許,也可以把發布的QoS調整成0。
IOT_MQTT_Yield的作用是什么?
IOT_MQTT_Yield的作用是嘗試接收數據。因此在需要接收數據時,例如訂閱和取消訂閱之后,發布QoS1消息之后,或是希望收到發布的數據時,都需要主動調用該函數。
IOT_MQTT_Yield參數timeout的意義是什么?
IOT_MQTT_Yield會嘗試接收數據,直到timeout時間到后才會退出。
IOT_MQTT_Yield與HAL_SleepMs的區別
IOT_MQTT_Yield與HAL_SleepMs都是阻塞一段時間,但是IOT_MQTT_Yield實質是去讀取數據,而HAL_SleepMs則是系統什么也不做,等待timeout。
如何循環接收消息?
需要循環調用IOT_MQTT_Yield,函數內自動維持心跳和接收數據。
訂閱了多個Topic,調用一次IOT_MQTT_Yield,能接收到多個Topic的消息嗎?
首先需要確定Topic的權限,是不是同時滿足發布和訂閱。如果是,調用一次IOT_MQTT_Yield,可以接收到多個packet。
MQTT連接方式,只能通過不停地調用IOT_MQTT_Yield來輪詢獲取數據嗎?
如果使用的TCP/IP協議棧,可以實現TCP主動通知上層有數據到達,可以改動實現事件觸發的方式來觸發IOT_MQTT_Yield。但是改動比較大,所以還請自行評估是否需要修改。
修改流程是:
調整utils_net.c里面socket的API,變成可以由TCP數據到達時回調的API。
當TCP主動通知上層有數據到達時,通知到MQTT服務器。讓MQTT服務器內部執行IOT_MQTT_Yield,這樣就可以不需要外部調用IOT_MQTT_Yield來讀取數據。
如果TCP無法做到主動上報數據,但OS支持多線程,也可以在MQTT-example里面再起一個thread,在這個thread里面以下代碼用于接收數據。收到數據時,觸發主線程進行數據處理,而主線程大部分時間可以用于處理其他邏輯。
while(1)
{
IOT_MQTT_Yiled(pclient, 200);
HAL_SleepMs(200);
}
如果使用的系統也不支持多線程,就只能把IOT_MQTT_Yield的timeout時間間隔減小,然后提高調用的頻率,在每次調用的時間間隔內執行其他操作,從而做到盡量減少對其他操作的阻塞。
什么情況下會發生訂閱超時(subscribe timeout)?
在2倍request_timeout_ms時間內,系統未接收到SUBACK packet時,會觸發訂閱超時,并通過event_handle函數發送超時通知。
請在訂閱之后,立刻執行IOT_MQTT_Yield嘗試讀取SUBACK,請勿使用HAL_SleepMs。
訂閱時,返回IOTX_MQTT_EVENT_SUBCRIBE_NACK
請檢查Topic的操作權限是否為訂閱。
如果發布報錯“no authorization”,請確認是否為發布權限。
MQTT發布的消息體大小限制
MQTT的協議包受限于IOT_MQTT_Construct里參數的write_buf和read_buf的大小。
MQTT協議包大小不能超過256 KB。超過大小限制的消息會被丟棄。
MQTT協議pub消息payload格式是怎么樣的?
物聯網平臺沒有制定pub消息payload的具體字段有哪些。您根據應用場景制定自己的協議,然后以JSON格式放到pub消息載體里面傳給服務端。
ota_mqtt升級時報錯“mqtt read buffer is too short”
MQTT設置的buffer過小,即mqtt_param的pread_buf和pwrite_buf申請過小造成的。可以根據實際需要修改OTA_MQTT_MSGLEN的大小。
是否可以使用MQTT直連的方式進行OTA升級?
可以。目前支持使用MQTT進行固件下載和OTA升級,但升級包大小有限制,最大為16 MB,適用于資源受限的設備。
打開MQTT over TLS,運行時提示MQTT創建失敗,返回錯誤碼0x2700
如果關閉MQTT over TLS則可以成功地訂閱和發布信息;打開MQTT over TLS時,建連失敗。首先確認mbedtls是否做了修改,這是用于傳輸層和應用層之間加密的功能,不能隨意更改。mbedtls沒有修改,則考慮系統時間是否正確,系統時間不對也會導致證書校驗失敗。
進行MQTT連接的時候,是否需要root.crt證書驗證?
若使用TLS進行MQTT接入,需要下載根證書。
若使用物聯網平臺提供的demo進行開發,無需再下載根證書,demo中已自帶證書。
物聯網平臺支持哪些QoS Level?
在MQTT協議、CCP協議下,阿里云物聯網平臺均支持QoS 0和QoS 1,但不支持QoS 2。