前言
在網絡通信中,心跳(Heartbeat)指的是一種周期性的消息,用于維持通信連接的活動狀態(tài)。心跳包的主要作用是檢測連接是否處于活動狀態(tài),及時發(fā)現(xiàn)連接異常并重新恢復連接,維護網絡通信的穩(wěn)定性和可靠性。
MQTT(Message Queuing Telemetry Transport)是一種輕量級、開放式的消息協(xié)議,用于在低帶寬和不可靠的網絡環(huán)境下傳輸消息。MQTT協(xié)議規(guī)定了PINGREQ和PINGRESP消息類型,用于實現(xiàn)心跳機制。PINGREQ消息是由客戶端向服務器發(fā)送的心跳包,PINGRESP消息是服務器回復的心跳包確認消息。
本文通過對mosquitto源碼(mosquitto-2.0.15)分析,介紹mosquitto如何實現(xiàn)基于MQTT協(xié)議的心跳和網絡重連機制。
一、MQTT各個版本對心跳機制的定義
不同版本的MQTT協(xié)議對心跳機制的定義略有不同,以下是各個版本對心跳機制的簡要介紹:
- MQTT v3.1.0
MQTT v3.1.0協(xié)議定義了keepalive選項,它是一個16位的值,表示客戶端與服務器之間的最大空閑時間。如果在這段時間內沒有任何通信活動,客戶端將發(fā)送PINGREQ消息給服務器,以確認服務器是否仍然在線。如果服務器沒有在規(guī)定時間內響應PINGREQ消息,客戶端將關閉連接。keepalive的默認值為60秒。 - MQTT v3.1.1
MQTT v3.1.1協(xié)議在v3.1.0的基礎上做了一些改進。其中,keepalive選項的最小值改為了1.5倍的發(fā)送間隔,最大值改為65535秒。這樣可以避免由于keepalive時間過短而導致頻繁發(fā)送PINGREQ消息,從而影響性能。此外,如果客戶端在規(guī)定時間內沒有收到服務器的響應,它可以重新發(fā)送PINGREQ消息,最多重試三次。 - MQTT v5.0
MQTT v5.0協(xié)議進一步改進了心跳機制。它定義了一個心跳超時屬性,用于指定服務器應該在多長時間內發(fā)送PINGREQ消息??蛻舳艘部梢栽赑INGREQ消息中設置超時屬性。如果服務器在規(guī)定時間內沒有響應PINGREQ消息,它將被視為已斷開連接。同時,MQTT v5.0還引入了會話恢復機制,它可以讓客戶端在斷開連接后重新連接并恢復之前的會話狀態(tài)。 - MQTT-SN
MQTT-SN(MQTT for Sensor Networks)是專門設計用于傳感器網絡的MQTT版本。它定義了一個心跳間隔選項,表示客戶端和網關之間的最大空閑時間。如果客戶端在規(guī)定時間內沒有發(fā)送消息,網關將發(fā)送PINGREQ消息。如果網關在規(guī)定時間內沒有收到任何消息,它將發(fā)送DISCONNECT消息,斷開連接。心跳間隔選項的默認值為30秒。
總的來說,MQTT協(xié)議的不同版本都對心跳機制進行了規(guī)定,旨在確??蛻舳撕头掌髦g的連接狀態(tài),并避免不必要的資源浪費。MQTT協(xié)議的心跳機制對于保證網絡穩(wěn)定性和消息傳遞的可靠性非常重要。
Mosquitto是一款常用的MQTT代理服務器,它支持多個MQTT協(xié)議版本。以下是Mosquitto版本與MQTT協(xié)議版本大體的對應關系:
- Mosquitto 0.x版本支持MQTT 3.1協(xié)議。
- Mosquitto 1.5.x版本支持MQTT 3.1和MQTT 3.1.1協(xié)議。
- Mosquitto 1.6.x以上版本支持MQTT 3.1、MQTT 3.1.1和MQTT 5.0協(xié)議。
不同版本的Mosquitto對應不同版本的MQTT協(xié)議,對于相同版本的MQTT協(xié)議,Mosquitto的實現(xiàn)與協(xié)議規(guī)范是相符合的。在Mosquitto中,心跳超時的實現(xiàn)遵循對應的MQTT協(xié)議規(guī)范,因此在不同版本的Mosquitto中,心跳部分的實現(xiàn)與相應版本的MQTT協(xié)議規(guī)范是一致的。
特別需要說明的是從Mosquitto 1.5.x開始,Mosquitto增加了對MQTT-SN的支持,同時包含了MQTT-SN網關功能,可以將MQTT-SN消息轉發(fā)到MQTT broker。雖然Mosquitto支持MQTT-SN,但是MQTT-SN和MQTT其他協(xié)議的使用方式略有不同,必須仔細閱讀Mosquitto的官方文檔,確保正確設置選項和命令行參數(shù)。
二、Mosquitto心跳和網絡重連機制的實現(xiàn)
MQTT 協(xié)議中的心跳機制用于維持客戶端和服務器之間的連接,確保連接不會因為長時間沒有數(shù)據(jù)交互而被斷開。Mosquitto MQTT 代理服務器中的心跳功能和網絡重連由服務器和客戶端共同完成:
1.心跳功能實現(xiàn)過程
1)客戶端向服務器發(fā)送心跳
在客戶端使用的struct mosquitto
結構體中,有一個 last_msg_in
字段和一個 last_msg_out
字段,分別表示客戶端最近一次收到消息(注意:這里是所有消息,包括PINGREQ、PINGRESP、PUBLISH等類型的消息)和發(fā)送消息的時間戳。當客戶端在一段時間內沒有發(fā)送任何消息時,主動向服務器發(fā)送一次心跳消息( PINGREQ 消息類型)。
客戶端發(fā)送心跳包之間的時間間隔由客戶端keepalive參數(shù)決定,發(fā)送心跳的時間應該是last_msg_out + keepalive
(不是last_msg_in + keepalive
)。
在客戶端使用 MQTT 協(xié)議連接到服務器時,通過設置 MQTT CONNECT 消息中的 keep alive 字段, keepaliv參數(shù)發(fā)送到服務器。
keepalive參數(shù)的設置過程如下:
在客戶端,mosquitto源碼定義了兩個重要的數(shù)據(jù)結構struct mosq_config
和struct mosquitto
,分別用于存儲mosquitto客戶端的配置信息和運行時狀態(tài)和信息。對于keepalive
參數(shù),首先需要在struct mosq_config
的對象cfg中設置,然后在連接前拷貝到struct mosquitto
結構體對象。
對于cfg->keepalive參數(shù),客戶端可以用三種方式確定(三種方式后面會覆蓋前面):
(1)第一次清空struct mosq_config對象cfg數(shù)值,并對部分參數(shù)賦初值,其中cfg->keepalive = 60;
(2)如果客戶端配置文件配置了keepalive參數(shù),在初始化函數(shù)中賦值cfg->keepalive;
(3)用命令行參數(shù)設置的參數(shù)設置keepalive參數(shù),在初始化函數(shù)中賦值cfg->keepalive。
2)服務器接收和回應來自客戶端的心跳
當 Mosquitto 服務器接收到客戶端的心跳包后,發(fā)送 PINGRESP 消息到此客戶作為響應。同時更新鏈表中保存的此客戶端struct mosquitto
結構體中的 last_msg_in
成員變量,記錄最后一次接收到此客戶消息的時間戳。
3)客戶端接收來自服務器的心跳響應
Mosquitto 客戶端接收來自服務器的心跳響應。當客戶端接收到來自服務器的心跳響應時,更新struct mosquitto
結構體中 last_msg_in
成員變量,設置為當前的時間戳 。
2.斷線的判定和重連
1)客戶端
客戶端當前正在使用的struct mosquitto
結構體實例中保存著當前狀態(tài)和相關信息,其中包括客戶端 ID、連接參數(shù)、訂閱信息、回調函數(shù)等。如果一定時間客戶端沒有收到任何消息,則可以認為連接已經斷開,這個超時時間就是keepalive
參數(shù),而struct mosquitto
結構體中的last_msg_in
則記錄了客戶端最后一次收到消息的時間。換句話說如果在last_msg_in + keepalive
內未能收到任何消息,可以認為連接已經斷開。此時,客戶端向服務器發(fā)送DISCONNECT`消息進行斷開連接操作,并嘗試重新連接服務器。
2)服務器
在Mosquitto服務器中,當一個客戶端連接到服務器時,Mosquitto服務器將客戶端加入到 客戶端列表中。判斷客戶端連接超時就是通過客戶端列表中的最后連接時間來實現(xiàn)的,當客戶端和 Mosquitto 服務器之間建立連接時,會向服務器發(fā)送一個 CONNECT
消息,消息中有一個 keepalive
參數(shù),用來設置客戶端需要在多長時間內發(fā)送至少一個 MQTT 消息或心跳包來保持連接。如果在 keepalive 值的兩倍時間內,Mosquitto 服務器沒有接收到任何來自客戶端的 MQTT 消息或心跳包,那么服務器就會判定客戶端連接已經超時。
在Mosquitto中,如果發(fā)現(xiàn)客戶端連接超時,或收到客戶端發(fā)送來的DISCONNECT 消息,服務器會關閉連接并從客戶端列表中刪除該客戶端。這個過程并不會自動刪除客戶端所有的數(shù)據(jù)。如果需要刪除客戶端所有的數(shù)據(jù),可以使用Mosquitto提供的on_disconnect
或on_client_disconnect
回調函數(shù)來執(zhí)行相關操作,用戶可以在這些回調函數(shù)中進行相關的清理操作。
在MQTTv5中有一項新特性,即服務器可以使用
mosquitto.conf
文件中的max_keepalive
參數(shù),通過發(fā)送CONNACK
報文中的Max Keep Alive字段覆蓋原來客戶端設置的保持活動值keepalive
。如果服務器端將這個參數(shù)設置為0,意味著不會進行任何keepalive
檢查,換句話說,即使收不到任何消息,客戶端與服務器的連接也不會斷開。
3)小結
Mosquitto客戶端或服務器是否斷開網絡與心跳機制并無直接關系。心跳機制是為了當客戶端與服務器出現(xiàn)長時間無需交換數(shù)據(jù)時,用于保持客戶端與服務器之間的連接狀態(tài)。
三、若干實現(xiàn)細節(jié)
1. 相關數(shù)據(jù)結構
1)每個客戶端的狀態(tài)和信息struct mosquitto
結構體
在 Mosquitto 2.0.15 版本中,這個結構體的定義在 lib/mosquitto_internal.h
文件中,當它用于客戶端時,表示 Mosquitto 客戶端的狀態(tài)和相關信息,包括客戶端 ID、連接參數(shù)、訂閱信息、回調函數(shù)等。
當這個結構體用于服務器的時候同樣表示單個 MQTT 客戶端連接的狀態(tài)和信息,但會用,記錄所有連接的客戶端信息,客戶端 ID、連接參數(shù)、訂閱信息、遺囑消息等。
在 Mosquitto 服務器中,每個已連接的客戶端都生成一個 struct mosquitto
結構體實例。服務器內部使用哈希表(Hash Table)組織和管理客戶端數(shù)據(jù)。而這個哈希表則由struct mosquitto_db
結構體中的一個成員變量contexts_by_id
進行關聯(lián)。
2)服務器管理客戶端 struct mosquitto_db
結構體
struct mosquitto_db
是 mosquitto 服務器的數(shù)據(jù)結構,用于內部管理連接到服務器的客戶端信息、訂閱信息和已發(fā)布消息等許多重要狀態(tài)信息。contexts_by_id
是 struct mosquitto_db
結構中的一個成員變量,它是一個哈希表,用于將客戶端 ID(Client ID)與客戶端上下文(Client Context)相關聯(lián)。
struct mosquitto_db {
/* ... */
struct mosquitto *contexts_by_id; /* 客戶端上下文哈希表(按客戶端ID索引) */
/* ... */
};
具體來說,當客戶端連接到 mosquitto 服務器時,客戶端需要使用一個唯一的客戶端 ID,用于標識該客戶端。客戶端 ID 可以用來查找客戶端的相關信息,例如其訂閱的主題、已發(fā)布的消息等。contexts_by_id
哈希表用于將客戶端 ID 映射到相應的客戶端上下文,以便更快速地訪問該客戶端的相關信息,或者將新的客戶端上下文插入到哈希表中。
需要注意的是,在 MQTT 協(xié)議中,Client ID 可以由客戶端指定,也可以由服務器自動生成,但需要保證唯一性。如果客戶端在發(fā)送 CONNECT 消息時沒有指定 Client ID,服務器會自動生成一個唯一的 Client ID。一般情況下,服務器會根據(jù)一定的規(guī)則生成 Client ID,例如可以使用時間戳、隨機數(shù)、MAC 地址等信息生成唯一的標識符。如果客戶端在發(fā)送 CONNECT 消息時指定了 Client ID,服務器將使用該 ID 來標識該客戶端。在實際應用中,通常建議客戶端使用一個固定的、唯一的 Client ID 來連接服務器。例如,可以使用設備的序列號、MAC 地址、IP 地址等信息作為 Client ID,以便在服務器端管理和維護客戶端連接狀態(tài)和消息訂閱等信息。
3)服務器自身狀態(tài)和信息 struct mosquitto__listener
結構體
struct mosquitto__listener
結構體用于 mosquitto 服務器本身的信息,如監(jiān)聽地址和端口等。mosquitto 服務器可以同時監(jiān)聽多個端口,每個監(jiān)聽器可以綁定一個特定的主機名或 IP 地址。在服務器運行期間,如果有新的連接請求到達監(jiān)聽器,服務器將使用 socks
數(shù)組中的文件描述符來處理這些連接。
4)服務器配置信息 struct mosquitto__config
結構體
struct mosquitto__config
是 mosquitto 服務器用于表示配置選項的結構體。該結構體定義在 mosquitto_broker_internal.h
頭文件中。主要用于表示 mosquitto 服務器的配置選項,這些選項包括監(jiān)聽地址和端口、持久化存儲、日志輸出、身份驗證等。在服務器啟動時,服務器將使用 struct mosquitto__config
中的選項來配置服務器的行為。具體來說,服務器將從配置文件中讀取配置選項并將其存儲在 struct mosquitto__config
結構體中,然后使用這些選項來初始化服務器。
5)客戶端配置信息 struct mosq_config
結構體
struct mosq_config
是 mosquitto 客戶端使用的結構體,用于表示 MQTT 連接和消息傳輸?shù)呐渲眠x項。其中包含了大量的配置選項,用于指定客戶端連接 MQTT 代理服務器的方式、訂閱主題、發(fā)布消息等行為,以及設置連接屬性、發(fā)布消息的屬性、訂閱主題的屬性等,這些選項可以通過命令行參數(shù)、配置文件或者代碼中直接設置。用于保持客戶端連接的是其中的keepalive
參數(shù)。
struct mosq_config {
/* ... */
int keepalive;
/* ... */
};
`keepalive` 參數(shù)是一個以秒為單位的時間間隔,用于指定客戶端和服務器之間的最大允許空閑時間。
2. 主要用到的函數(shù)
客戶端生命周期
Mosquitto 客戶端的生命周期包括創(chuàng)建、連接、開啟線程接收消息(訂閱/發(fā)布、心跳)、斷開連接和銷毀等階段。
1)創(chuàng)建客戶端實例:mosquitto_new
mosquitto_new
函數(shù)是 Mosquitto C 語言客戶端庫的入口函數(shù),用于創(chuàng)建一個新的 Mosquitto 客戶端實例,是使用 Mosquitto 客戶端庫進行 MQTT 通信的第一步。
函數(shù)原型如下:
struct mosquitto *mosquitto_new(const char *id, bool clean_start, void *userdata);
參數(shù)解釋如下:
-
id
:客戶端的標識符,可以是任何字符串,如果為NULL
則表示由服務器自動生成一個唯一的標識符。 -
clean_start
:一個布爾值,表示客戶端是否希望使用“清除會話”功能。如果為true
,則客戶端會話結束后,服務器將清除客戶端的訂閱和 QoS 1 和 QoS 2 消息,否則服務器會將這些信息保留下來,以便在下一次客戶端連接時恢復。建議在大多數(shù)情況下將其設置為true
。 -
userdata
:一個指向用戶數(shù)據(jù)的指針,用于存儲客戶端特定的上下文信息,例如程序狀態(tài)或回調函數(shù)的指針等。
函數(shù)返回一個struct mosquitto
類型的指針,表示創(chuàng)建的 Mosquitto 客戶端實例。如果創(chuàng)建失敗,返回NULL
。
在創(chuàng)建 Mosquitto 客戶端實例后,需要調用client_connect
函數(shù)連接到 MQTT 代理服務器,并通過mosquitto_loop_start
函數(shù)啟動客戶端消息循環(huán)。之后可以通過mosquitto_subscribe
函數(shù)訂閱主題、通過mosquitto_publish
函數(shù)發(fā)布消息等來實現(xiàn) MQTT 客戶端的功能。
2)連接MQTT服務器:client_connect
client_connect
函數(shù)是 Mosquitto 客戶端代碼庫中用于連接到 MQTT 服務器的函數(shù),其定義如下:
int client_connect(struct mosquitto *mosq, struct mosq_config *cfg)
該函數(shù)的參數(shù) mosq
是一個 Mosquitto 客戶端實例,而 cfg
則是一個 Mosquitto 客戶端的配置參數(shù)結構體。
在函數(shù)內部,首先會檢查 Mosquitto 客戶端實例 mosq
和配置參數(shù)結構體 cfg
是否為空。然后,調用 mosquitto_loop_start
函數(shù)開啟線程運行 Mosquitto 客戶端消息循環(huán),返回線程是否啟動成功。同時檢查客戶端的認證信息、超時時間和遺囑消息等參數(shù)是否設置正確等,連接成功后將相應參數(shù)發(fā)送到 MQTT 服務器。
為了 client_connect
函數(shù)能夠正確連接到 MQTT 服務器,運行的程序需要正確設置服務器地址、端口號及其他連接參數(shù),并確保服務器當前正處于正常工作狀態(tài)。
3)創(chuàng)建線程開啟客戶端的消息循環(huán):mosquitto_loop_start
mosquitto_loop_start
函數(shù)是 Mosquitto 客戶端代碼庫中用于啟動一個消息循環(huán)線程的函數(shù),其定義如下:
int mosquitto_loop_start(struct mosquitto *mosq)
該函數(shù)的參數(shù) mosq
是一個 Mosquitto 客戶端實例。
在函數(shù)內部,首先會檢查 Mosquitto 客戶端實例 mosq
是否為空,然后調用 mosquitto__threaded_client
函數(shù)創(chuàng)建一個消息循環(huán)線程,并將其保存到客戶端實例的內部結構體中。同時,為了確保線程的安全性和穩(wěn)定性,還會設置一些線程屬性和回調函數(shù),并檢查線程是否創(chuàng)建成功。如果線程創(chuàng)建成功,則返回 MOSQ_ERR_SUCCESS
;否則,返回相應的錯誤代碼。
需要注意的是,在使用 mosquitto_loop_start
函數(shù)啟動消息循環(huán)線程時,需要保證客戶端實例已經正確初始化,并且在線程創(chuàng)建之后,需要及時處理客戶端的事件和消息(訂閱/發(fā)布、心跳),并在必要的情況下關閉線程和釋放相關資源。
4)訂閱消息:mosquitto_subscribe
mosquitto_subscribe
函數(shù)是 Mosquitto 客戶端代碼庫中用于向 MQTT 3.1/3.1.1 服務器訂閱一個主題的函數(shù),其定義如下:
int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos)
該函數(shù)的參數(shù) mosq
是一個 Mosquitto 客戶端實例,mid
是一個整型指針,用于返回訂閱消息的 ID,sub
是一個字符串,表示要訂閱的主題,qos
表示訂閱的 QoS 等級。
在函數(shù)內部,首先會檢查 Mosquitto 客戶端實例 mosq
是否為空,并檢查客戶端是否已經連接到 MQTT 3.1/3.1.1 服務器。然后,調用 mosquitto__mid_generate
函數(shù)生成訂閱消息的 ID,并調用 mosquitto_send_subscribe_v3
函數(shù)向服務器發(fā)送訂閱消息,并檢查是否發(fā)送成功。如果成功,則將消息 ID 保存到參數(shù) mid
中,并返回 MOSQ_ERR_SUCCESS
;否則,返回相應的錯誤代碼。
需要注意的是,在使用 mosquitto_subscribe
函數(shù)訂閱主題時,需要先確??蛻舳艘呀浾_連接到服務器,并且在訂閱主題之后,需要及時處理服務器返回的消息和事件,并在必要的情況下取消訂閱主題和釋放相關的資源和內存,以避免程序出現(xiàn)異?;蛸Y源泄露等問題。同時,為了提高程序的穩(wěn)定性和安全性,也需要注意避免重復訂閱相同的主題或訂閱不存在的主題。
5)發(fā)布消息:mosquitto_publish
mosquitto_publish
函數(shù)是 Mosquitto 客戶端代碼庫中用于向 MQTT 3.1/3.1.1 服務器發(fā)布一條消息的函數(shù),其定義如下:
int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
該函數(shù)的參數(shù) mosq
是一個 Mosquitto 客戶端實例,mid
是一個整型指針,用于返回消息 ID,topic
是一個字符串,表示要發(fā)布消息的主題,payloadlen
表示消息內容的長度,payload
是一個指針,指向消息內容的緩沖區(qū),qos
表示發(fā)布消息的 QoS 等級,retain
表示消息是否需要保留。
在函數(shù)內部,首先會檢查 Mosquitto 客戶端實例 mosq
是否為空,并檢查客戶端是否已經連接到 MQTT 3.1/3.1.1 服務器。然后,調用 mosquitto__mid_generate
函數(shù)生成消息 ID,并調用 mosquitto_send_publish_v3
函數(shù)向服務器發(fā)送消息,并檢查是否發(fā)送成功。如果成功,則將消息 ID 保存到參數(shù) mid
中,并返回 MOSQ_ERR_SUCCESS
;否則,返回相應的錯誤代碼。
需要注意的是,在使用 mosquitto_publish
函數(shù)發(fā)布消息時,需要先確??蛻舳艘呀浾_連接到服務器,并且在發(fā)送消息之后,需要及時處理服務器返回的消息和事件,并在必要的情況下取消發(fā)布消息和釋放相關的資源和內存,以避免程序出現(xiàn)異?;蛸Y源泄露等問題。同時,為了提高程序的穩(wěn)定性和安全性,也需要注意避免重復發(fā)送相同的消息或發(fā)送無效的消息。
6)心跳超時檢測和處理:mosquitto_loop_misc
mosquitto_loop_misc
函數(shù)是 Mosquitto 客戶端代碼庫中的一個循環(huán)處理函數(shù),用于在后臺線程中處理客戶端的網絡事件、心跳消息和超時事件等,其定義如下:
int mosquitto_loop_misc(struct mosquitto *mosq)
該函數(shù)的參數(shù) mosq
是一個 Mosquitto 客戶端實例。
在函數(shù)內部,首先會檢查 Mosquitto 客戶端實例 mosq
是否為空,并檢查客戶端是否已經連接到 MQTT 3.1/3.1.1 服務器。然后,調用 mosquitto__check_keepalive
函數(shù)檢查客戶端是否需要發(fā)送心跳消息,并檢查客戶端是否需要重新連接到服務器。接著,調用 mosquitto__packet_alloc
函數(shù)為客戶端分配一個數(shù)據(jù)包,并調用 mosquitto__send_pingreq
函數(shù)向服務器發(fā)送心跳消息。最后,調用 mosquitto__check_pending_write
函數(shù)檢查是否有待發(fā)送的消息,并檢查是否需要將發(fā)送消息的緩沖區(qū)寫入網絡套接字中。
需要注意的是,在使用 mosquitto_loop_misc
函數(shù)處理客戶端網絡事件、心跳消息和超時事件時,需要先確保客戶端已經正確連接到服務器,并且在處理事件之后,需要及時取消事件和釋放相關的資源和內存,以避免程序出現(xiàn)異?;蛸Y源泄露等問題。同時,為了提高程序的穩(wěn)定性和安全性,也需要注意避免重復發(fā)送心跳消息或發(fā)送無效的數(shù)據(jù)包。
7)斷開連接:mosquitto_disconnect
mosquitto_disconnect
函數(shù)是 Mosquitto 客戶端代碼庫中用于與 MQTT 3.1/3.1.1 服務器斷開連接的函數(shù),其定義如下:
int mosquitto_disconnect(struct mosquitto *mosq)
該函數(shù)的參數(shù) mosq
是一個 Mosquitto 客戶端實例。
在函數(shù)內部,首先會檢查 Mosquitto 客戶端實例 mosq
是否為空,并檢查客戶端是否已經連接到 MQTT 3.1/3.1.1 服務器。然后,調用 mosquitto__disconnect
函數(shù)斷開客戶端與服務器的連接,并檢查是否斷開成功。如果成功,則返回 MOSQ_ERR_SUCCESS
;否則,返回相應的錯誤代碼。
需要注意的是,在使用 mosquitto_disconnect
函數(shù)與 MQTT 3.1/3.1.1 服務器斷開連接時,需要先確??蛻舳艘呀浾_連接到服務器,并且在斷開連接之后,需要及時釋放相關的資源和內存,以避免程序出現(xiàn)異常或資源泄露等問題。同時,為了保證客戶端的穩(wěn)定性和安全性,也需要注意避免在未斷開連接的情況下重復調用該函數(shù)。
8)銷毀客戶端實例:mosquitto_destroy
mosquitto_destroy
函數(shù)是 Mosquitto 客戶端代碼庫中用于銷毀 Mosquitto 客戶端實例的函數(shù),其定義如下:
void mosquitto_destroy(struct mosquitto *mosq)
該函數(shù)的參數(shù) mosq
是一個 Mosquitto 客戶端實例。
在函數(shù)內部,首先會檢查 Mosquitto 客戶端實例 mosq
是否為空,并調用 mosquitto_disconnect
函數(shù)與 MQTT 3.1/3.1.1 服務器斷開連接。然后,釋放客戶端的資源和內存,包括客戶端實例、消息緩沖區(qū)、網絡套接字等。
需要注意的是,在使用 mosquitto_destroy
函數(shù)銷毀 Mosquitto 客戶端實例時,需要先確??蛻舳艘呀浾_連接到服務器,并且在銷毀客戶端之前,需要及時釋放相關的資源和內存,以避免程序出現(xiàn)異常或資源泄露等問題。同時,為了提高程序的穩(wěn)定性和安全性,也需要注意避免在未銷毀客戶端實例的情況下重復創(chuàng)建客戶端實例或使用客戶端實例的相關函數(shù)。
服務器對客戶端的支撐
在 Mosquitto 客戶端的生命周期中,服務器扮演了重要的角色,負責管理客戶端連接狀態(tài)、消息傳輸和路由等工作。在客戶端的連接、訂閱和消息發(fā)布等操作中,服務器會提供相應的響應和支持,為客戶端提供消息傳輸和管理的服務。
具體來說,在客戶端的生命周期中,服務器需要配合客戶端進行如下工作:
-
連接:服務器需要接收來自客戶端的 CONNECT 消息,對客戶端進行身份驗證和授權,并分配 Client ID、維護連接狀態(tài)等。
-
訂閱/發(fā)布:服務器需要接收客戶端的 SUBSCRIBE 和 PUBLISH 消息,對訂閱和發(fā)布進行管理和路由,并將消息傳遞給訂閱方或發(fā)布到指定的主題。
-
斷開連接:服務器需要處理客戶端的 DISCONNECT 請求,關閉與客戶端的連接,清除客戶端的訂閱和 QoS 1、QoS 2 消息等信息,并在需要時發(fā)送 Last Will and Testament 消息。
-
消息傳輸保證:服務器需要支持消息傳輸?shù)?QoS 0、QoS 1 和 QoS 2 等級,并對消息傳輸進行保證,以確保消息傳輸?shù)目煽啃院驼_性。文章來源:http://www.zghlxwxcb.cn/news/detail-779667.html
因此,在 Mosquitto 客戶端的生命周期中,服務器與客戶端密切配合,為客戶端提供必要的支持和服務,同時也維護和管理整個 MQTT 系統(tǒng)的穩(wěn)定和安全運行。文章來源地址http://www.zghlxwxcb.cn/news/detail-779667.html
到了這里,關于mosquitto心跳和網絡重連機制(基于MQTT協(xié)議)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!