使用Netty实现一个IM即时通讯系统的设计

实战篇一的代码结构:
代码的层级结构如上所示,接下来,我们将会一个个模块对逻辑进行讲解。
1、登录
1)实现逻辑
不管是长连接还是短连接,鉴权这个动作都是要有的,我相信这个功能模块,大家是很好理解的。我这里就不在过多的赘述了,具体实现步骤如下所示:
1、前后端建立 ws 连接
2、前端发送登录类型的报文,如下所示:
{    token: 2,    type: 10}  
token:这里的 token,就是用户登录标识,大家可以根据自己所依赖的业务系统,进行修改。
type:这里表示消息报文的类型,本文所有类型定义如下所示:
user_login (10, 用户上线)
user_login_resp (11, 用户上线响应)
heartbeat_timeout (30, 心跳超时)
ping (40, 心跳)
pong (41, 心跳响应)
chat (80, 聊天),
chat_resp (81, 聊天响应)
ack (90, 确认)
ack_resp (91, 确认响应)
unknown (0, 未知类型)
示例代码如下图所示,wsmsgdispatcher.dispatch
消息类型
3、后端对 token 进行校验,校验成功就记录用户登录信息。
示例代码如下图所示,userloginprocessor.login
登录业务逻辑
2)具体效果
主要的业务代码我们已经讲解完毕了,接下来我们来看看效果:
用户登录
从上图,我们可以看到,我们登录的两个用户都成功了,并且返回了对应的用户信息。
2、维持连接、心跳检测
这个模块的功能,其实我们在原理篇二的时候已经讲过了具体的实现方案 了,这里也不再过多的赘述了,我们直接来看具体实现方法吧。
1)维持连接
1、前端每10秒发送一次心跳消息,报文如下所示:
{    type: 40,    fromid: 2}  
注:前端发送的每个消息,理论上都是需要带上用户表示的,后端都是需要进行鉴权操作的。我们这里为了方便讲解(偷懒,bushi)将这部分逻辑进行了简化,大家在具体实现的时候,记得一定要加上 鉴权逻辑 。
2、后端检测,用户是否还在线,如果在线,则刷新用户的最新在线时间,并回复 pong 消息。
示例代码如下图所示,heartbeatprocessor.process
维持连接1
维持连接2
2)心跳检测
这里主要是基于 idlestateevent 事件实现的。
textwebsocketframehandler 继承 simplechannelinboundhandler 类,并实现 usereventtriggered 方法,具体代码如下所示:
心跳检测
这里详细说一下,三种事件的区别:
readeridletimeseconds: 读超时。即当在指定的时间间隔内没有从 channel 读取到数据时,会触发一个 reader_idle 的 idlestateevent 事件。
writeridletimeseconds: 写超时。即当在指定的时间间隔内没有数据写入到 channel 时,会触发一个 writer_idle 的 idlestateevent 事件。
allidletimeseconds: 读/写超时。即当在指定的时间间隔内没有读且没有写操作时,会触发一个 all_idle 的 idlestateevent 事件。
所以,我们这里检测 all_idle 事件即可。
3)具体效果
维持连接效果如下所示:
维持连接效果
心跳检测效果如下所示:
心跳超时效果1
心跳超时效果2
3、聊天消息
聊天消息模块主要分为两部分:
消息接收:客户端推送消息到服务端
消息推送:服务端将消息推送到指定的客户端
这边主要的难点在于,服务端将消息推送到指定的客户端,具体场景有2种情况:
消息的发送者和消息的接受者,在同一台服务器上建立的 ws 连接,这种情况,就很好处理,直接在服务器上找到建立的 ws 连接,然后将消息推送给对应的客户端。
消息的发送者和消息的接受者,在不同的服务器上建立的 ws 连接,这种情况就比较复杂,实现方案也很多,比较简单的实现方式就是,发送一条广播消息,让对应的服务器,将消息推送到指定的客户端。
本文由于是 单机版 的 im,所以只会有第一种情况发生,第二种情况就留给大家自由发挥了。
1)消息接收
具体步骤如下所示:
1、客户端发送类型为80的报文,如下所示:
{        type: 80,        fromid: 1,        toid: 2,        content: {        contenttype: 1,        body: 测试消息        }        }  
2、服务端(chatprocessor)对消息进行处理,具体代码如下所示:
消息接收
2)消息推送
具体步骤如下所示:
1、获取消息接受者所连接的服务器 ip 地址 2、判断当前服务器 ip 地址是否和上面的 ip 地址相同,如果相同则推送消息,否则转发给目标服务器
具体代码如下所示:
消息推送
3)具体效果
1、我们先登录两个用户,分别是张三、李四,如下图所示:
聊天登录
2、张三发送消息给李四,如下图所示:
张三发送消息给李四
3、李四发送消息给张三,如下图所示:
李四发送消息给张三
4、消息 ack
因为网络环境异常或者其他异常状况的发送,可能会出现消息推送失败的情况,这时候就需要 消息 ack 机制和重试,来保证我们的消息可以推送成功。
1)消息 ack 机制
具体步骤如下:
1、客户端收到 80 类型的消息,解析并发送 ack 报文,如下所示:
{        type: 90,        msgid: 2bfea133-72a8-4315-82aa-80049fe4fb7b        }  
2、服务端收到 ack 消息,变更消息状态(ackprocessor),具体代码如下图所示:
消息ack
2)消息重试
这里因为是单机版 im,所以直接采用 springboot-job 实现,job 代码如下所示:
消息重试


区块链将如何改变员工的敬业度
无人机细分市场与相互竞争力促进行业发展
3D视觉感知技术企业奥比中光正式登陆科创板,总市值114.92亿
华为云发布云原生2.0全景图,结果和过程的双重可信的高质量
特斯拉正式发布召回计划,马斯克亲自劝诫谨慎购买
使用Netty实现一个IM即时通讯系统的设计
一种有效的蓄电池在线监测方案
ICCAD 2022,Imagination邀您共聚厦门!
BM34063A单片机控制电路包含DC-to-DC所需的主要功能转换器
详解机器学习分类算法KNN
苹果手机遇冷!iPhone6暴跌至历史最低价,比国产的小米6还便宜,你会选择谁?
仙工智能迎来了今年的收官展会:东莞智博会
信号放大器的原理及作用
ADI的µModule技术正在加快工业4.0革命
将开发套件从原型转变为解决方案
换代升级成主流选择,海信AI电视引领新潮流
AliOS Things电源管理框架怎么满足物联网设备低功耗需求
矢量网络分析仪器简介
华硕GT-AC5300电竞路由器评测 配置信号确实讲究
城市级智慧停车解决方案实现线上线下全场景闭环功能