MQTTLens的訊息發布欄位,包含QoS(品質)與Retained(保留)選項。
發布訊息時,若Retained(保留)訊息選項為true(勾選),MQTT代理人將保存此主題訊息。其後如有新的訂閱者,或者之前斷線的訂閱者重新連線,都能收到最新一則保留訊息(但並非全部訊息喔~)。
QoS(品質)設定
QoS代表發布者與代理人,或者代理人與訂閱者之間的傳輸品質。MQTT定義了0, 1和2三個層級的品質設定(實際支援情況依伺服器軟體而定,Mosquitto伺服器全都支援):
- 0:最多傳送一次(at most once)
- 1:至少傳送一次(at least once)
- 2:確實傳送一次(exactly once)
用寄信來比喻,QoS 0就像寄平信,不保證訊息會送達。
補充說明,MQTT裝置之間的訊息傳遞基於TCP/IP,在正常連線狀態下,TCP能確保訊息封包都能抵達目的地。在網路階層架構中,「MQTT程式」屬於應用層,它產生的訊息交給下一層(TCP)處理,但MQTT程式並不清楚最底層的網路是否壅塞甚至斷線,所以才說,MQTT不保證能交付訊息。
QoS 1品質設定則像寄送掛號信;收訊者(如:代理人)收到訊息之後,會回應PUBACK訊息(publish acknowledgement,發布確認)給發布者,確認有收到訊息。在「品質」設定為1或2的情況下,MQTT訊息檔頭後面會夾帶一個稱為packetId(封包ID)的識別碼,收訊者回應的PUBACK訊息也會傳回相同的識別碼提供發布者確認。
假如一段時間過後,發布者沒有收到PUBACK回應,它會認定訊息沒有送達,因而重新傳送一次訊息。然而,如果代理人有收到訊息,但是在它傳送回應時,發布者因連線故障而漏接回應。發布者會誤以為對方沒收到訊息而再次傳送,導致訂閱者重複收到相同訊息。
最後是QoS 2設定。在此設定模式之下,當收訊者收到訊息時,它將回覆PUBREC(publish received,已收到發布訊息),並且暫存訊息的「封包識別碼」,以防重複處理相同的訊息。當發布者收到PUBREC回應時,將傳送PUBREL(publish release,釋放發布訊息)給代理人,代理人會先把訊息傳送給訂閱者,然後回應PUBCOMP(publish complete,發布完成)並刪除之前暫存的訊息。
上圖以「發布者」和「代理人」之間的連線示範;假如「代理人」和「訂閱者」之間的傳送品質設定為1或2,且Clean Session(清除會談,參閱下文)設定為false,而「代理人」在送出訊息之後,沒有收到回應,它將儲存訊息,直到用戶端重新連線,代理人將再次發送這些訊息。
如果佈署的物聯網裝置採用的網路很穩定(如:有線網路),或者在感測器頻繁地發送數據,即使遺漏少數樣本數據也無妨的情況下,只需採用QoS 0設定。
假若你的應用場合需要確實接收每一則訊息,而且你的用戶端程式可以過濾(或者不在乎)重複的訊息,那麼QoS 1設定已足敷使用,因為它不像QoS 2那樣佔用較多網路、處理器資源和傳輸時間(某些網路連線計費是以byte為單位)。
請問老師有MQTT 使用android studio 寫的client端 然後用thingSpeak 當作server端的應用實例嗎
或是哪裡有推薦的 感恩
感謝好文章. 請問, 關於qos=1, 請問是否有保證 broker 到 subscriber 之間必然傳達? 謝謝
如上文所述「假如一段時間過後,發布者沒有收到PUBACK回應,它會認定訊息沒有送達,因而重新傳送一次訊息。」
thanks,
jeffrey
感謝版主這一系列MQTT的文章,圖美好讀易懂。
想順便請問文章中的圖都是用什麼軟體作出來的?
Thank you!!
Adobe Flash(註:Flash在2015年末更名為Animate CC)
thanks,
jeffrey
請問QoS1 的設定中,receiver有確保message收到的順序性嗎?
假設順序ABCD,如果publisher沒有收到B的ACK的期間內會先丟出C跟D,還是就會重複發送B直到收到B的ACK後才繼續發送CD呢?
感謝
根據MQTT官方技術文件(5.0版)的這個4.6 Message ordering(訊息排序)單元說明,伺服器傳遞訊息時,必須將每一則主題當作「排序的主題(Ordered Topic)」,但是伺服器軟體也可以透過某些設定機制,允許一則或多則主題不被當作「排序的主題」。其中的第一點也提到伺服器會按照順序重傳(此規則適用於QoS 1和QoS 2訊息)。