IM系统中,特别是在企业应用场景下,消息的已读未读状态是一个强需求。
功能看起来很酷,但用起来是一言难尽(上班族心里苦.... )。实际上,技术实现也并不容易。
那么,对于已读未读状态:
1)如果是私聊:消息的阅读状态比较容易实现,在性能和存储上也不存在问题;2)如果是群聊:考虑到存储和处理性能,特别当处于一个云环境时,如何高效地处理群聊的已读未读状态是一个非常值得探讨的话题。
这里提到的“高效”含3个方面:
1)存储空间;2)处理速度;3)传输字节数。
本文将从服务端的角度来探讨已读未读状态,在具体的技术实现上对于存储空间占用方面的思路差异。
【im即时通讯开发(群聊消息的已读未读功能)】已读未读状态交互流程
发送者发送的IM聊天消息,在接收者阅读消息后,是否要求阅读者通知已读,可能是由系统配置、组织配置、群组配置等决定,也可能由发送者根据业务需求决定。以下的讨论,均假设消息需要已读未读状态。
文章图片
客户端与服务端之间,关于阅读状态的命令只需3个,每个命令含请求和应答。
通知消息已读(私聊、群聊通用)
当小宝阅读了一条或若干条消息,需向服务端发送消息已读通知:“众爱卿发的x+y+z消息,朕已阅”。
服务端收到小宝的已读通知时,需完成以下事项:
1)存储消息的已读状态;
2)返回应答给小宝;
3)向已读列表的消息的原始发送者通知消息已读。
对于第“3)”步:
1)私聊的场合,比较好理解,就是发送给私聊的对方;
2)群聊的场合,可很不一样:因为小宝发送的已读消息列表,可能是由众爱卿发送的。考虑这种假设:张三、李四、王五发出的群聊消息,被小宝一下都阅读了,那么小宝发出的已读通知包含的消息列表,需要被IMS分解成3个已读通知(3个不同的消息列表),分别通知给张三、李四、王五,通知内容是“爱卿(不含'"众")发的这些消息,朕已阅”。
查询消息的未读人数(私聊、群聊通用)
消息的发送者,加载消息列表到聊天窗口时,可能需要展示消息是否被已读。
对群聊而言,显示的信息可能是n人未读的提示,那么需要向服务端查询消息的未读人数,由于客户端可能在UI显示自己发出的多条消息,需支持一次请求查询多条消息。
以未读人数的方式来表示消息的阅读状态,统一了私聊、群聊的查询,使得客户端-服务端间的接口更简单,同时使客户端的实现逻辑更统一。
就像下面这样:
1)对于私聊:如果未读人数n>0,表示消息未读;
2)对于群聊:直接显示n人未读即可,当然,当n等于0时表示全部已读。
查询群消息的已读、未读人员清单(群聊)
当客户端希望显示某一条群聊消息的已读、未读人员列表,需向服务端发起查询。
几种具体的已读未读状态存储思路探讨
基本约定
群聊的阅读状态比私聊复杂,因此这里着重讨论群聊的阅读状态。
假设群成员数是n,各个客户端立即IM服务端发送已读通知。服务端需存储每个人的阅读状态,包括那些未读的成员。由于群的成员清单可能变化,比如今天增加了一个成员,则昨天发的消息、与今天发的消息,其接收者列表不一样。
即:
1)同一个群的不同消息,对应的接收者列表可能不一样。
2)换言之,每一条消息都需要记录完整的接收者列表和已读人员列表。
为了方便讨论,本章假设群成员有640人为前提。即时通讯聊天软件开发可以咨询蔚可云开发。
文章图片
存储思路1
每一条消息都维护:
1)接收人员列表receiver_list;
2)已读人员列表read_list。
具体是:
1)IM Server收到一条消息时,用全体群成员构建receiver_list;
2)IM Server收到群成员对这条消息的已读通知时,将此成员加入到read_list。
客户端获取此消息的数据:
1)当需要获取未读人数时,用receiver_list的个数减去read_list的个数;
2)当需要获取已读、未读人员列表时,需用receiver_list减去read_list得到未读人员列表。
那么,思路1每条消息的存储空间是:
640个ID + 不定数量的已读人员ID
存储思路2
每一条消息维护:
1)未读人员列表unread_list;
2)已读人员列表read_list。
具体是:
1)IM Server收到一条消息时,用全体群成员构建unread_list;
2)IM Server收到群成员对这条消息的已读通知时,将此成员从unread_list移出,同时加入到read_list。
客户端获取此消息的数据:
1)当需要获取未读人数时,直接计算unread_list的个数;
2)当需要获取已读、未读人员列表时,直接返回unread_list和read_list。
那么,思路2每条消息的存储空间是:
未读人员ID + 已读人员ID,合计640个ID
思路2的实现,占用的空间是案1的0.5倍~1.0倍。即案2占用的空间少,但在每次收到客户端的已读通知时,比案1多了一个操作:从unread_list进行减员。