1、启动im项目的时候,所有的im节点都注册到zkpath对应的 /im/gate节点,然后自己有iplist项目(tomcat)里面维护着这些节点的信息,然后每个节点如果有变化的时候,都会通知到所有的iplist,更新这些节点,同时iplist还会循环注册watch,因为watch是一次性的,然后客户端android,ios,web端调用iplist来通过roundrobin轮训获取节点信息ip:port,然后返回给客户端,以供客户端发起长连接请求.

2、比如客户端发了消息,然后服务端返回过程中断掉了网,出现了未发送的红点,这个时候如何确定保证唯一性,也就是不能发重复的消息,去重?

ios和android都有一个唯一id生成功能,能够保证去重

3、比如刚开始用户a在 im1机器上面,突然间网络断开了,等im1连接到了im2机器上面的时候这个时候用户是和im1交互呢,还是和im2交互呢?

每个用户和channel关系通过一个map<user, channel>维护在其中一台机器上面,同时redis里面还做了记录Map<user, ip:port>,当用户切换到了im2的时候,这个时候redis里面记录了两条用户对应的记录,当用户连接到了im2的时候,这个时候系统就会通过redis里面的user对应的ip:port去调用一次im1服务器,去把用户和channel的关系给解除了.

4、空闲连接处理

由于ios切换到了后台,就停止了和服务端的交互,然后android只要你登录了就会一直交互,redis记录着每个用户的最后一次聊天记录信息,然后如果十分钟没有聊天的话,就自动断开连接,节省服务器无畏的开销


5、消息由于用户端网络不好没有推送成功

5.1、用户A断线重连始终连接的是同一台服务器

A发消息给B,这个时候,用户A会先发给服务端,然后服务端开始推送,如果服务端推送的过程中,用户和服务端的网络断开了的话,那么这个时候A发送的消息就到达不了B,这个时候就等待下次用户A登录的时候去拉取。

5.2、用户A断线重连的是不同的服务器

A发消息给B,这个时候,用户A会先发给服务端,然后服务端开始推送,如果服务端推送的过程中,用户和服务端的网络断开了的话,那么这个时候A发送的消息就到达不了B,这个时候就等待下次用户A登录的时候去拉取,如果A登录到了不同的服务器的话,那么这个时候首先检测redis里面有没有更多的登录记录,有的话,就获取到上次登录的Map<user, ip:port>,然后调用对应的机器里面保存的map<user, channel>关系,然后就把当前的登录用户和ip:port记录进去,然后去聊天记录表拉取对应的未读消息返回给用户端。


6、用户登录

服务器端登录信息验证成功后生成String类型的Token(用户id+时间戳+随机数,有效期一周)返回给客户端,此Token用于断线重连的验证信息

开启心跳检测,客户端每空闲5s发送一个心跳包,服务器端每空闲6s计一次心跳失败

username和channel维护在一个Map集合中

7、断线重连

使用Token尝试重连,然后做后面的其他未读消息,之类的校验以及处理


8、项目启动顺序:







Logo

开源、云原生的融合云平台

更多推荐