Netty+springboot开发即时通讯系统笔记(二)

基础业务模块开发

1.数据库设计,在csdn上搞定了

2.用户单表增删改查。

全局异常处理:RestControllerAdvice在类上,ExceptionHandler在方法上,里面有个value值,可以写java提供的异常以及自定义异常

3.好友:

弱好友关系,关注粉丝

强好友关系:qq,正常数据库中写一条就可以了,但是查询的时候很麻烦,所以需要写两条查询合并到一起。所以这里采用写两份的方法,A加B好友。插入from A,to B和from B ,to A ,这样查询就只需要一条语句了。

校验好友关系:1双方都添加了2from方删除3to方删除4双方删除

在这里插入图片描述

查询语句:先查出自己的好友列表信息,再以toid为自己的id查出对称的好友列表信息,用inner join连接起来,on条件是a.fromid=b.toid and b.fromid=a.toid。用这两份关联数据作为from条件,查出不同的状态。

select a.fromId,a.toId,(

case

 when a.status =1 and b.status =1 then 1

when a.status !=1 and b.status =1 then 2

when a.status =1 and b.status !=1 then 3

when a.status !=1 and b.status !=1 then 4

end

)as status

from(select from_id as fromId,to_id as toId,if(status=1,1,0)as status from im_friendship where from_id="user1" and to_id in('user2',"user3","user4")) as a
inner join
(select from_id as fromId,to_id as toId,if(status=1,1,0)as status from im_friendship where to_id="user1" and from_id in('user2',"user3","user4"))  as b 
on a.fromId=b.toId and a.toId=b.fromId

不是好友的就做特殊处理,在查询之前用stream流给所有校验对象封装成一个map,然后合并这个和另一个map,不是好友的状态就返回0.

 Map<String, Integer> result = req.getToIds().stream().collect(Collectors.toMap(Function.identity(), s -> 0));
//将 req.getToIds() 返回的列表元素转化为 Map 对象,其中列表元素作为键(key),对应的值(value)都设置为0。

tcp网关

1.登录与登出

用户session存在channels的map集合中作为key,channel作为值。

private static final Map<UserClientDto, NioSocketChannel> CHANNELS = new ConcurrentHashMap<>();

登录存入redis里,用map,key存不同的端pc,web,value存用户信息。同时存入channels中。

   RMap<String, String> map = redissonClient.getMap(msg.getMessageHeader().getAppId() + Constants.RedisConstants.UserSessionConstants + loginPack.getUserId());
            map.put(msg.getMessageHeader().getClientType()+":" + msg.getMessageHeader().getImei()
                    ,JSONObject.toJSONString(userSession));

登出就删除session以及redis

2.心跳检测

写一个HeartBeatHandler 继承ChannelInboundHandlerAdapter,重写userEventTriggered用户自定义事件,evt转为CustomEvent,然后可以判断读写的空闲状态以实现心跳检测。

超时给用户状态改为离线。

3.rabbitmq

tcp服务调用逻辑层服务,可以使用http,rpc,mq,选择mq最大的优点是可以进行限流,

  1. 消息(Message):消息是 RabbitMQ 中的基本数据单元,它由消息体和消息属性组成。消息体是要传递的实际数据,而消息属性包含一些元数据,如消息的路由键、优先级等。
  2. 交换机(Exchange):交换机是消息的接收和分发中心。生产者将消息发布到交换机,而交换机根据指定的路由键将消息路由到一个或多个队列。
  3. 队列(Queue):队列是消息的存储和传递载体。消费者从队列中接收消息,并按照一定的规则进行处理。
  4. 绑定(Binding):绑定是交换机和队列之间的关联关系。它定义了交换机如何将消息路由到队列。

工作模式

  1. 简单模式(Simple Mode):也称为点对点模式(Point-to-Point),是最简单的工作模式。在简单模式中,一个生产者将消息发送到一个队列,一个消费者从该队列中接收并处理消息。每个消息只能被一个消费者消费。
  2. 工作队列模式(Work Queue Mode):也称为任务队列模式(Task Queue),用于在多个消费者之间共享任务。在工作队列模式中,一个生产者将消息发送到一个队列,多个消费者从该队列中竞争接收消息,并进行处理。每个消息只能被一个消费者消费。
  3. 发布/订阅模式(Publish/Subscribe Mode):用于将消息广播给多个消费者。在发布/订阅模式中,一个生产者将消息发送到一个交换机,交换机将消息广播给绑定到它的所有队列。每个消费者都会从自己的队列中接收消息并进行处理。
  4. 主题模式(Topic Mode):主题模式是发布/订阅模式的扩展,它允许消费者根据消息的主题进行选择性订阅。在主题模式中,一个生产者将消息发送到一个交换机,并指定一个主题作为消息的路由键。消费者可以使用通配符表达式来定义自己感兴趣的主题,交换机将消息根据主题进行匹配和路由。
  5. RPC 模式(Remote Procedure Call Mode):RPC 模式用于实现分布式系统中的远程调用。在 RPC 模式中,客户端发送请求消息到一个队列,服务端接收并处理请求,并将结果返回给客户端。客户端等待并接收服务端的响应消息。

4.注册tcp服务到zookeeper

5.服务改造

分布式netty,每个用户所在的netty可能不在一个节点上,他们之间的通讯怎么解决呢?

1.广播(发布-订阅),A给B发送消息,A去给所有节点发送一份,找到B所在的节点,完成通讯。

2.一致性hash,给每个用户session得到哈希值对应的节点,A给B发消息就可以先计算出B的节点,然后通过mq投递消息。

3.路由表,在redis中记录一张表,然后发消息的时候在这张表里查。

6.多端登录

单平台登录,2,3,多平台登录

所以登录需要 userID(用户id),appId(应用id),clientType(web,安卓,ios),imei(标识唯一的设备)。

1 只允许一端在线,手机*/电脑/web* 踢掉除了本client+imel的设备

2 允许手机*/电脑的一台设备 *+ web在线 踢掉除了本client+imel的非web*端设备*

3 允许手机和电脑单设备 + web 同时在线 踢掉非本client+imel的同端设备

4 允许所有端多设备登录 不踢任何设备

使用redis的发布订阅模式,上线后把信息推送给所有netty服务端,接收到之后就给他根据不同的登录策略做处理。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JJpZh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值