聲明:微信客戶端協議是二進制協議而且加密,難以分析協議具體編碼格式,我不做逆向工程。只是簡單抓包分析業務的實現流程,在這里記錄下來用於參考學習,並不是破解協議。
IM產品的多點登陸邏輯特別復雜,很難做到很好的用戶體驗,就像新版mac handoff 功能也不少人在噴。
微信最開始並不支持多點登陸,后來陸續增加的Web版、Mac版,但並不是完整意義的客戶端,要說只是輔助輸入。
微信允許: 一個移動端(下面稱之為主客戶端) + 一個web/mac 同時在線(下面稱之為從客戶端),web/mac 只能接收在線消息、發消息,不記錄消息歷史。這樣多點邏輯就變得相對簡單很多了。
存儲
服務器不用保存完整消息歷史,通過客戶端對push消息的ack保證消息送達,協議保證消息至少一次推送到主客戶端,然后消息即可刪除;服務器只存儲未下發到主客戶端的消息。
多點時:主客戶端依然采用Push推送消息(只是應該會保留一小段時間消息記錄等待從Sync),從客戶端Sync消息;如果主不在線,消息記錄不會刪除,等主重新連上下載離線消息。
服務器不存儲消息歷史,一個是安全,再者節省硬件成本,大量短消息的存儲和讀取成本是非常高的,因為基本都是隨機IO。whatapp 用500台機器,支撐1億在線,雖然有100w/s 消息,只離線消息存儲量是很少的。
未讀數同步
這個很好解決,如果客戶端知道自己處於多端在線情況下時,進入會話時,需要告訴服務器消息已讀。消息已讀也保存為一條消息,再通過Sync協議,同步到另外的客戶端。web 微信會調用webwxstatusnotify 同步未讀。
未讀變化也當成一條消息存儲,且只在多端情況下存在,單點在線時未讀數由客戶端維護。
刪除消息
不管是否多點在線任何刪除消息操作都會同步到服務器,避免刪除的消息下次有不小心同步回來了,服務器可能及時刪除、也可能長期保存,客戶端每次上報就沒錯了。
移動客戶端消息刪除不會同步到 web版。
自己同步自己
每個操作(發消息、清未讀等),應答后,因為SyncKey 變化了,Sync協議上會產生一個空的Sync操作用於更新SyncKey。
為啥不通過應答更新SyncKey? 並發情況直接更新會造成丟消息問題,也保證協議的統一性。
對於主客戶端:
- 單點在線時發消息,並不會同送空的SyncKey,SyncKey應該是通過應答防護,節省同步流量。怎么防止丟消息呢?
猜想是這樣: 請求時帶上SyncKey(local), 服務器在inc SyncKey得到SyncKey(current) == SyncKey(local) 時,直接返回SyncKey(current),否則返回Sync(local) 並推送New SyncKey Notify。因為此時確保客戶端沒有未收消息,壞情況應答比新消息慢,也不會有啥問題。
- 多點在線時,發消息和從客戶端一樣,也會自己同步自己