十年網(wǎng)站開發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
MQTT設(shè)計(jì)了一套保證消息穩(wěn)定傳輸?shù)臋C(jī)制,包括消息應(yīng)答、存儲和重傳。

創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供定襄網(wǎng)站建設(shè)、定襄做網(wǎng)站、定襄網(wǎng)站設(shè)計(jì)、定襄網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、定襄企業(yè)網(wǎng)站模板建站服務(wù),10余年定襄做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
為了保證消息被正確的接收
在這套機(jī)制下,提供了三種不同層次QoS(Quality of Service):
QoS 是消息的發(fā)送方(Sender)和接受方(Receiver)之間達(dá)成的一個協(xié)議:
::: warning
QoS是Sender和Receiver之間的協(xié)議,而不是Publisher和Subscriber之間的協(xié)議。
換句話說,Publisher發(fā)布了一條QoS1的消息,只能保證Broker能至少收到一次這個消息;
而對于Subscriber能否至少收到一次這個消息,還要取決于Subscriber在Subscribe的時候和Broker協(xié)商的QoS等級。
:::
QoS0等級下,Sender和Receiver之間一次消息的傳遞流程如下:
Sender向Receiver發(fā)送一個包含消息數(shù)據(jù)的PUBLISH包,然后不管結(jié)果如何,丟掉已發(fā)送的PUBLISH包,一條消息的發(fā)送完成。
QoS1要保證消息至少到達(dá)一次,所以有一個應(yīng)答的機(jī)制。Sender和Receiver的一次消息的傳遞流程如下:
1.Sender向Receiver發(fā)送一個帶有數(shù)據(jù)的PUBLISH包,并在本地保存這個PUBLISH包;
2.Receiver收到PUBLISH包以后,向Sender發(fā)送一個PUBACK數(shù)據(jù)包,PUBACK數(shù)據(jù)包沒有消息體(Payload),在可變頭中有一個包標(biāo)識(Packet Identifier),和它收到的PUBLISH包中的Packet Identifier一致。
3.Sender收到PUBACK之后,根據(jù)PUBACK包中的Packet Identifier找到本地保存的PUBLISH包,然后丟棄掉,一次消息的發(fā)送完成。
但是消息傳遞流程中可能會出現(xiàn)問題:
相比QoS0和QoS1,QoS2不僅要確保Receiver能收到Sender發(fā)送的消息,還需要確保消息不重復(fù)。它的重傳和應(yīng)答機(jī)制就要復(fù)雜一些,同時開銷也是最大的。QoS2下,一次消息的傳遞流程如下所示:
1.Sender發(fā)送QoS為2的PUBLISH數(shù)據(jù)包,數(shù)據(jù)包 Packet Identifier 為 P,并在本地保存該P(yáng)UBLISH包;
2.Receiver收到PUBLISH數(shù)據(jù)包后,在本地保存PUBLISH包的Packet Identifier P,并回復(fù)Sender一個PUBREC數(shù)據(jù)包,PUBREC數(shù)據(jù)包可變頭中的Packet Identifier為P,沒有消息體(Payload);
3.當(dāng)Sender收到PUBREC,它就可以安全的丟棄掉初始Packet Identifier為P的PUBLISH數(shù)據(jù)包。同時保存該P(yáng)UBREC數(shù)據(jù)包,并回復(fù)Receiver一個PUBREL數(shù)據(jù)包,PUBREL數(shù)據(jù)包可變頭中的Packet Identifier為P,沒有消息體;
4.當(dāng)Receiver收到PUBREL數(shù)據(jù)包,它可以丟掉保存的PUBLISH包的Packet Identifier P,并回復(fù)Sender一個可變頭中 Packet Identifier 為 P,沒有消息體(Payload)的PUBCOMP數(shù)據(jù)包;
5.當(dāng)Sender收到PUBCOMP包,那么認(rèn)為傳輸已完成,則丟掉對應(yīng)的PUBREC數(shù)據(jù)包;
上面是一次完整無誤的傳輸過程,然而傳輸過程中可能會出現(xiàn)以下情況:
針對上述的問題,較為詳細(xì)的處理方法如下:
Receiver收到PUBREL數(shù)據(jù)包后,正式將消息遞交給上層應(yīng)用層,投遞之后銷毀Packet Identifier P,并發(fā)送PUBCOMP數(shù)據(jù)包,銷毀之前的持久化消息。
之后不管接收到多少個PUBREL數(shù)據(jù)包,因?yàn)闆]有Packet Identifier P,直接回復(fù)PUBCOMP數(shù)據(jù)包即可。
在 MQTT 協(xié)議中,從 Broker 到 Subscriber 這段消息傳遞的實(shí)際 QoS 等于:Publisher 發(fā)布消息時指定的 QoS 等級和 Subscriber 在訂閱時與 Broker 協(xié)商的 QoS 等級,這兩個 QoS 等級中的最小那一個。
Actual Subscribe QoS = MIN(Publish QoS, Subscribe QoS)
如果 Client 想接收離線消息,必須使用持久化的會話(Clean Session = 0)連接到 Broker,這樣 Broker 才會存儲 Client 在離線期間沒有確認(rèn)接收的 QoS 大于 等于1 的消息。
在以下情況下你可以選擇 QoS0:
在以下情況下你應(yīng)該選擇 QoS1:
在以下情況下你應(yīng)該選擇 QoS2:
最近遇到一個MQTT上傳包體達(dá)到了5M,且上傳速度較快,處理完畢后內(nèi)存也沒有下降的趨勢,只有當(dāng)服務(wù)器內(nèi)存不夠用的時候才會回收一小部分內(nèi)存,導(dǎo)致內(nèi)存飛漲,同一服務(wù)器上的其他服務(wù)根本無法提供穩(wěn)定的服務(wù)。
這種情況基本可以確定為byte[]太大,直接分配到堆上面了,而堆上的大對象要2代GC才能夠回收,但是二代GC又懶又慢,啥時候回收這部分內(nèi)存完全看心情。
雪崩的時候沒有一片雪花是無辜的
1. 解決數(shù)組租用的問題
既然心里已經(jīng)大概有了解決的方案那這事情就很明朗了
一個固定數(shù)組的租用使用 ArrayPoolT 這個對象去進(jìn)行數(shù)組的租用,但是這個玩意對于使用者有點(diǎn)不太友好,申請的長度并不是實(shí)際需要的長度,這對于一些需要使用固定長度進(jìn)行計(jì)算的地方就很蛋疼了。所以需要對這個進(jìn)行一個封裝,將實(shí)際需要的長度存儲起來作為這個數(shù)組的長度,超過的全部作廢掉。
那這個類的基本設(shè)計(jì)就應(yīng)該是下面這樣的,有一個 Length 去決定從 ArrayPoolT 租出來的數(shù)組到底有多少是可用長度。
2.要對數(shù)組進(jìn)行指針操作.NET給我們提供了 Span 的API,但是這個沒辦法在Class中使用,所以只能使用它的同胞兄弟 MemoryT ,這些玩意在網(wǎng)上到處都是介紹的,我在這里就不介紹了。
3.如果要減少流拷貝就需要將這個類加上一個 Clone 的函數(shù),直接讓其他人調(diào)用Clone函數(shù),就不會出現(xiàn)流拷貝太多導(dǎo)致多次分配堆的問題。
那么綜上所需,出來的封裝類應(yīng)該就是這樣的
再針對這個搞點(diǎn)拓展函數(shù)
搞定 完事
原地址:
原文鏈接:
MQTT客戶端軟件MQTT.fx的使用詳解
使用說明
mqtt.fx打開后的主頁面如下:
點(diǎn)擊齒輪進(jìn)行連接設(shè)置
本地連接設(shè)置:
用戶信息設(shè)置:
SSL安全證書設(shè)置:
網(wǎng)絡(luò)代理設(shè)置:
遺囑設(shè)置:
連接測試
1、啟動mosquitto
地址,下一步配置使用
2、在主機(jī)中打開MQTT.FX軟件
設(shè)置連接信息
IP為mosquitto所在的IP,端口號默認(rèn)為1883。
點(diǎn)擊進(jìn)行連接
連接成功以后可以進(jìn)行發(fā)布訂閱。