用微信给别人发信息如果对方关机他开机能收到信息吗
发布网友
发布时间:2022-04-29 13:10
我来回答
共3个回答
热心网友
时间:2023-10-08 18:36
微信好友通过微信发送微信信息给对方,对方在关机情况下无法接收到微信信息,只有开机登陆微信账户就可以接收到其它微信好友发送的微信信息。
热心网友
时间:2023-10-08 18:37
可以啊,你如果发的微信信息他开微信就会收到的
热心网友
时间:2023-10-08 18:37
不管是MQ(Msg Queue)的消息投递,还是单人实时聊天的消息投递,都需要通过应用层的超时、重传、确认、去重来保证消息的可靠投递。
但是,如果没有打开手机,没有登录微信,好友发给我的微信消息,有没有可能丢失呢?这是今天和大家分享的话题。
画外音:初步一想,离线消息存库不就好了么?往后看,会比你想象的更复杂。
接收方不在线,消息发送流程是怎么样的?
如上图所述,A给B发了一条消息,而B不在线,离线消息存储的流程如下:
画外音:在服务端会存储B的状态为offline。
(1) 用户A发送消息给用户B,通过server中转;
画外音:你猜,有没有可能不通过server中转,而AB直连呢?
(2) server查看用户B的状态为offline;
(3) server将消息存储到DB中;
(4) server返回用户A发送成功;
画外音:没毛病,对于发送方而言,消息落地DB就认为发送成功。
离线消息表如何设计?
很容易想到,消息业务有这样的一些关键属性:
t_offline_msg(
receiver_uid, // 离线消息接收方
msg_id, // 消息ID
time, // 消息发送时间
sender_uid, // 消息发送方
msg_type, // 消息类型
msg_content, // 消息内容
…
);
根据业务模式设计表结构。
画外音:下半句是,根据访问模式设计索引结构。
那么,离线消息的拉取过程如何呢?
B要拉取A给ta发送的离线消息,只需在
(receiver_uid(B), sender_uid(A))
上查询,然后把离线消息删除,再把消息返回B即可。
画外音:根据这个访问模式,要建立一个联合索引。
整体流程如上图所述:
(1) 用户B拉取用户A发送给ta的离线消息;
(2) server从DB中拉取离线消息;
(3) server从DB中把离线消息删除;
(4) server返回给用户B想要的离线消息;
画外音:没毛病,这个过程也不难想到。
BUT,用户B登录微信的时候,其实不止要拉取A发给他的离线消息,还需要拉取所有其他好友发给他的离线消息呀!
OK!如果用户B有很多好友,登陆时客户端需要对所有好友进行离线消息拉取。
客户端伪代码:
get B's friend-list; // 拉取B的好友列表
for(all uid in B's friend-list){ // 遍历所有好友uid
get_offline_msg(B,uid); // 拉取离线消息
}
我去,如果有1000个好友,难道要拉取1000次?有没有减少拉取次数的优化方法呢?
画外音:我的微信好友已满员,大家猜微信好友上限是多少?
先拉取各个好友的离线消息数量,真正查看离线消息时,才往服务器发送拉取请求,即按需拉取。
画外音:手机端为了节省流量,经常会使用这个按需拉取的优化。
除了减少流量的“按需拉取”优化,还有减少拉取次数的优化方案么?
当当当当!!!!
可以一次性通过receiver_uid即接收方ID,拉取所有好友发送给用户B的离线消息,把登录时与服务器的交互次数降低为了1次。
画外音:这样的话,离校消息表的访问模式就变为,只需要按照receiver_uid来查询了。
到客户端本地再根据sender_uid进行计算。
问题又来了,用户B一次性拉取所有好友发给ta的离线消息,消息量很大时,一个请求包很大,速度慢怎么办?
画外音:
老板,怎么这么难伺候呢?
请求次数多,你说瓶颈是网络,慢!
1次请求,你说报文大,瓶颈是带宽,又说慢!
到底要闹哪样?
分页拉取,是一种常见的优化方案。根据业务需求,先拉取最新的一页消息,再按需一页页拉取。
画外音:这是一个包大小与拉取次数的折衷。
任何设计方案都是折衷。
新的问题,离线消息会不会丢失,用户会不会收不到呢?
例如,上述步骤第三步执行完毕之后(删除了离线消息),第四个步骤离线消息返回给客户端过程中,服务器挂掉,路由器丢消息,或者客户端crash了,那离线消息岂不是丢了么。
画外音:数据库已删除,用户却还没看到。
如何保证离线消息的可达性?
如同在线消息的应用层ACK机制一样,离线消息拉时,不能够直接删除数据库中的离线消息,而必须等应用层的离线消息ACK,等客户端真的收到离线消息,才能删除数据库中的离线消息。
画外音:ACK机制,是消息可靠性传递的常见玩法,不管是在线消息,还是离线消息。
新的问题又出现了!
画外音:刨根问底,才是严谨的治学态度。
如果用户B拉取了一页离线消息,却在ACK之前crash了,下次登录时会拉取到重复的离线消息么?
拉取了离线消息却没有ACK,服务器不会删除之前的离线消息,故下次登录时系统层面还会拉取到。但在业务层面,可以根据msg_id去重,让用户无感知。
画外音:SMC理论,系统层面无法做到消息不丢不重,业务层面可以做到对用户无感知。
另一个问题,假设有N页离线消息,现在每个离线消息需要一个ACK,那么岂不是客户端与服务器的交互次数又加倍了?有没有优化空间?
画外音:优化是无止境的。
其实,不用每一页消息都ACK,在拉取第二页消息时相当于第一页消息的ACK,此时服务器再删除第一页的离线消息即可,最后一页消息再ACK一次。这样的效果是,不管拉取多少页离线消息,只会多一个ACK请求,与服务器多一次交互。
总结
“离线消息”的玩法,可能比大家想象的要复杂,常见的优化有:
(1) 对于同一个用户B,一次性拉取所有用户发给ta的离线消息,再在客户端本地进行发送方分析,相比按照发送方一个个进行消息拉取,能大大减少服务器交互次数;
(2) 按需拉取,是无线端的常见优化;
(3) 分页拉取,是一个请求次数与包大小的折衷;
(4) 应用层的ACK,应用层的去重,才能保证离线消息的不丢不重;
(5) 下一页的拉取,同时作为上一页的ACK,能够极大减少与服务器的交互次数;