不管是訊息佇列的訊息投遞,還是單人實時聊天的訊息投遞,都需要通過應用層的超時,重傳,確認,去重來保證訊息的可靠投遞。離線訊息的處理,根據實際業務需求來做處理。一般來說,要保證使用者的離線訊息不丟失,使用者上線後能夠獲取離線訊息。
1.a傳送訊息給b,通過伺服器server中轉;
2.server檢視b的狀態為offline離線;(服務端會快取使用者的狀態)
3.server將訊息儲存到資料庫db;
4.server返回使用者a,訊息傳送成功;(對於傳送方而言,訊息存到db,就認為傳送成功)
使用者b上線了,他要拉取a給他傳送的離線訊息,整體流程如下:
1.b向server拉取a給b傳送的離線訊息; (通過uid_b,uid_a在離線訊息表查詢)
2.server從db中獲取離線訊息;
3.server從db中刪除離線訊息;
4.server將b所需要的離線訊息返回給b.
這是最原始的場景。
實際上使用者登入後,可能要拉取所有好友的離線資訊,顯然他不能乙個乙個的去拉取,原因是要減少拉取次數,乙個合理的方式是按需拉取,即先拉取各個好友的離線訊息數量,真正檢視離線訊息時,才往伺服器傳送拉取請求。
進一步優化拉取次數:一次拉取b的所有好友的離線訊息,通過uid_b查詢離線訊息表,然後在客戶端本地,根據sender_uid進行計算,區分是哪個具體的好友訊息。
整體流程如下:
1.b向server拉取所有給b傳送的離線訊息; (通過receiver_uid=uid_b在離線訊息表查詢)
2.server從db中獲取離線訊息;
3.server從db中刪除離線訊息;
4.server將b所需要的離線訊息返回給b.
問題:一次請求返回所有資料,返回的報文資料可能過大,速度會很慢
方案:分頁拉取,根據業務需求,先拉取最新的一頁訊息,在按需一頁頁拉取。
整體流程如下:
1.b向server拉取所有給b傳送的離線訊息;
2.server從db中按頁獲取離線訊息;
3.server從db中按頁刪除離線訊息;
4.server將b所需要的離線訊息按頁返回給b.
問題1:如果先刪除離線訊息,再返回資料,在返回資料的過程中伺服器掛了,路由器丟失訊息,或者客戶端掛了,怎麼弄?
顯然需要用ack機制,離線訊息拉取時不能直接刪除資料庫中的離線訊息,而必須等應用層的離線訊息ack,等客戶端真的收到離線訊息,才能刪除資料庫中的離線訊息。
問題2:如果使用者b拉取了一頁訊息,卻在ack之前掛了,下次登入時會拉到重複的離線訊息嗎?
在系統層面,拉取了訊息但是沒有ack,伺服器不會刪除之前的離線訊息,故下次登入還會拉取到。但是在業務層面,可以根據msg_id去重,讓使用者無感知。
問題3:假如有n頁離線訊息,如果每頁訊息都需要乙個ack,那麼客戶端與伺服器的互動次數有加倍了,如何優化?
其實,不用每一頁都單獨ack一次,在拉取第二頁訊息時相當於第一頁訊息的ack,此時伺服器再刪除第一頁訊息即可,最後一頁訊息在ack一次,整個過程僅僅是在最後一頁拉取成功之後加了個ack,中間是用後面的拉取請求同時做為上一次的ack。這樣的效果是,不管拉取多少頁資料,只會多乙個ack請求,與伺服器多一次互動。
「離線訊息」的玩法,場景的優化,有:
Openfire 離線訊息的處理機制
離線訊息的處理策略類。1.靜態成員變數type 用來設定訊息的處理型別,主要包括 打回 丟棄 儲存,在超限情況下打回 儲存,在超限情況下丟棄 2.靜態成員變數quota 標識最大所能儲存的message總和大小預設為100k。3.支援offlinemessagelistener事件 只要實現此介面並...
handler訊息處理機制
handler主要用來更新ui 因為涉及到執行緒安全,android必須在ui執行緒 即主線程 裡才能更新ui,在其他執行緒裡更新ui會報錯,而一些耗時的操作又必須通過開啟新的執行緒來執行,這就要用到handler來傳遞訊息了。在主線程中建立乙個handler的例項,並重寫handlermessag...
非同步訊息處理機制
借鑑 為什麼不能在子執行緒更新ui?1 ui是非執行緒安全的,主線程和子執行緒同時更新ui的話會導致錯誤,如ui錯亂之類的。2 ui更新是很耗效能的,更別說為了執行緒安全加鎖了,最簡單的方法就是更新ui的操作放到乙個執行緒中,即主線程 handler機制 looper 維持乙個thread物件以及m...