1. 程式人生 > >openfire因為網路不穩定而造成訊息丟失的解決方案

openfire因為網路不穩定而造成訊息丟失的解決方案

       1               2

C1 ------- S ------- C2

訊息丟失

狀態:C1線上,但C2因為網路問題,或是程序被殺死,並且此時伺服器還沒及時傳送ping 進行判斷C2是否線上。

第一種情況:

此時,當C1向C2傳送訊息時,步驟1可以順利完成,而由於此時S並不知道C2已離線,會和正常情況一樣傳送訊息至C2,但是S不會收到來自步驟2產生的任何錯誤與提示,S則傳送訊息後結束整個訊息處理,等到C2恢復正常後則會丟失來自C1的訊息

第二種情況:

該情況為第一種情況的逆向。當C2向C1傳送訊息時,步驟2不會完成,因為C2根本沒有連線到S,但是C2卻沒有任何來自步驟2的錯誤提示,導致C2認為訊息已發出,待C2恢復正常後C2斷線時的訊息全部丟失

初步解決方案(待驗證):

第一種情況:

擴充套件S離線訊息處理機制,不光在客戶端正常離線時儲存客戶端收到的訊息,非正常離線也會儲存,所以在S傳送訊息至C2置前或置後進行處理,置前是先判斷C2是否真正線上,實現方式可以採用傳送ping,如果有ping的迴應側傳送訊息,否則儲存離線訊息;置後則是先發訊息,傳送後等待終端的訊息回執(XEP-0184)。

第二種情況:

增加客戶端訊息回執功能(XEP-0184),傳送方傳送訊息時註明需要接收方成功收到訊息後進行規定格式的訊息回執,以確保訊息的正常送達

新增訊息回執的訊息傳送過程


以下節點在伺服器端擷取

<!--1、C1(使用者63)傳送訊息至C2(使用者1580),並且註明需要訊息回執-->
<message to="
[email protected]
"id="Fdb6V-15"> <body>訊息內容</body> <requestxmlns="urn:xmpp:receipts"></request><!--需要訊息回執--> </message> <!--2、S(伺服器)把接收到的訊息進行處理(增加from屬性)後,傳送至C2(使用者1580)--> <message to="[email protected]"id="Fdb6V-15" from="[email protected]
/Smack"> <body>訊息內容</body> <requestxmlns="urn:xmpp:receipts"></request> </message> <!--3、C2(使用者1580)接收到來自C1(使用者63)的訊息後,傳送訊息回執,message節點的type屬性為normal--> <message to="[email protected]/Smack"id="1guiN-36" type="normal"> <receivedxmlns="urn:xmpp:receipts"id="Fdb6V-15"></received><!--received節點下的id的值為已接收到訊息的id值(重要)--> </message> <!--4、S(伺服器)把接收到的訊息進行處理(增加from屬性)後,傳送至C2(使用者1580)--> <message to="[email protected]/Smack"id="1guiN-36" type="normal" from="[email protected]/Smack"> <receivedxmlns="urn:xmpp:receipts"id="Fdb6V-15"></received> </message>

下圖上方為客戶端C1發出的節點,下方為C2接收到的節點


下圖下方為C2接收到資訊後發出的訊息回執,上方為C1所收到的訊息回執


到此為止,上面的測試與產生的資料都是建立在正常的情況之下,也就是C1與C2都是線上的,都是可以收的到訊息的,下面進行非正常情況下的測試。

一、 收訊息方離線

二、 收訊息方非正常線上(不能收到訊息,但是伺服器認為它可以收到訊息)

測試一:

第一步:

我們先關閉一個使用者,使其下線,之後再用另一個使用者進行傳送訊息,測試如下:


測試中傳送了八條訊息,但是收到的訊息卻是空白的


此時已說明對方未接收到訊息。

第二步:

我們讓離線的使用者重新上線,觀察其狀態。


接收方接收來自伺服器的離線訊息後,傳送了相應的訊息回執到訊息傳送方,下圖為訊息傳送方接收到的訊息回執:


其實上面的測試結果是沒有什麼爭議的,按照openfire的離線訊息處理也應該能猜到,但是下面的另一種測試就有點出乎意料了。

第一步:發訊息方線上,收訊息方離線,發訊息方發訊息後,就離線

第二步:收訊息方上線,可以收到訊息,併發送訊息回執,

第三步:發訊息方上線,可是它卻沒有收到任何訊息回執。

不論這種情況是否正確,或是它產生的原因,先放置在這,最後再總結。

測試二:

第一步:我們先讓接收方登入,之後檢視openfire的使用者列表,確認其真正線上,之後,拔掉接收方的網線,模擬網路變差的情況,之後檢視openfire使用者列表,發現接收方依舊線上。

第二步,登入訊息傳送方,之後傳送若干條訊息,發現並沒有訊息回執,說明對方未收到訊息

第三部:重新使接收方真正上線,發現沒有任何離線訊息,同樣,也沒有訊息回執。

總結:

不論XEP-0184最重要的目的是什麼,此時的表現,它不能完全解決我們的問題,因為它太依賴訊息的接收者,並且似乎主要是終端受影響,伺服器不需要做什麼,所以根據我們的需求整理一下解決方案,時序圖如下:


第一部分:訊息從傳送方到伺服器,這裡增加訊息回執(XEP-0184),可以確保訊息真正傳送至伺服器,並且在等待訊息回執時可以增加介面的進度圖示顯示,或是在訊息回執超時後進行標記顯示(下圖為QQ截圖)


第二部分:此時伺服器以接收到訊息,準備傳送至訊息接收方。此時,伺服器需要傳送ping(XEP-0199)實時驗證終端是否真正線上(可能離線或是非正常離線),是否可以接受訊息,當條件不允許時,伺服器會儲存離線訊息,否則,傳送訊息。