首页 > 代码库 > [微信协议分析] 多点登陆
[微信协议分析] 多点登陆
IM产品的多点登陆逻辑特别复杂,很难做到很好的用户体验,就像新版mac handoff 功能也不少人在喷。
微信最开始并不支持多点登陆,后来陆续增加的Web版、Mac版,但并不是完整意义的客户端,要说只是辅助工具。
微信允许: 一个移动端(下面称之为主客户端) + 一个web/mac 同时在线(下面称之为从客户端),web/mac 只能接收在线消息、发消息,不记录消息历史。这样多点逻辑就变得相对简单很多了。
存储
服务器不用保存完整消息历史,通过客户端对push消息的ack保证消息送达,协议保证消息至少一次推送到主客户端,然后消息即可删除;服务器只存储未下发到主客户端的消息。
多点时:主客户端依然采用Push推送消息(只是应该会保留一小段时间消息记录等待从Sync),从客户端Sync消息;如果主不在线,消息记录不会删除,等主重新连上下载离线消息。
服务器不存储消息历史,一个是安全,再者节省硬件成本,大量短消息的存储和读取成本是非常高的,因为基本都是随机IO。whatapp 用500台机器,支撑1亿在线,100w/s 消息,只离线消息存储量是很少的。
未读数同步
这个很好解决,如果客户端知道自己处于多端在线情况下时,进入会话时,需要告诉服务器消息已读。消息已读也保存为一条消息,再通过Sync协议,同步到另外的客户端。web 微信会调用webwxstatusnotify 同步未读。
未读变化也当成一条消息存储,且只在多端情况下存在,单点在线时未读数由客户端维护。
自己同步自己
每个操作(发消息、清未读等),应答后,因为SyncKey 变化了,Sync协议上会产生一个空的Sync操作用于更新SyncKey。
为啥不通过应答更新SyncKey? 并发情况直接更新会造成丢消息问题
对于主客户端:
- 单点在线时,SyncKey通过应答,节省同步流量。怎么防止丢消息呢?
猜想是判断 请求时带上SyncKey(local), 服务器在inc SyncKey得到SyncKey(current) == SyncKey(local) 时,直接返回SyncKey(current),否则返回Sync(local) 并推送New SyncKey Notify。因为此时确保客户端没有未收消息,坏情况应答比新消息慢,也不会有啥问题。
- 多点在线时,发消息和从客户端一样,也会自己同步自己
为何不保持和单点时一样呢,暂时还没想明白
[微信协议分析] 多点登陆