启动rocketmq 报错_netty无缝切换rabbitmq、activemq、rocketmq实现聊天室功能

23d0643c50e157d3659d19499b08f1ea.png
a84f839ae1bb9a1afe02e631f776fab8.png

netty的pipeline处理链上的handler:需要IdleStateHandler心跳检测channel是否有效,以及处理登录认证的UserAuthHandler和消息处理MessageHandler

30987bda943949543ea42125c33da1b1.png


对于所有连进来的channel,我们需要保存起来,往后的群发消息需要依靠这些channel

93778e2ddc2510e66adb576e7ae98bf2.png

登录后,channel就变成有效的channel,无效的channel之后将会丢弃

public static boolean saveUser(Channel channel, String nick, String password) {        UserInfo userInfo = userInfos.get(channel);        if (userInfo == null) {            return false;        }        if (!channel.isActive()) {            logger.error("channel is not active, address: {}, nick: {}", userInfo.getAddr(), nick);            return false;        }        // 验证用户名和密码        if (nick == null || password == null) {            return false;        }        LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();        lambdaQueryWrapper.eq(Account::getUsername, nick).eq(Account::getPassword, password);        Account account = accountMapperStatic.selectOne(lambdaQueryWrapper);        if (account == null) {            return false;        }        // 增加一个认证用户        userCount.incrementAndGet();        userInfo.setNick(nick);        userInfo.setAuth(true);        userInfo.setId(account.getId());        userInfo.setUsername(account.getUsername());        userInfo.setGroupNumber(account.getGroupNumber());        userInfo.setTime(System.currentTimeMillis());        // 注册该用户推送消息的通道        offlineInfoTransmitStatic.registerPull(channel);        return true;    }

当channel关闭时,就不再接收消息。unregisterPull就是注销信息消费者,客户端不再接取聊天消息。此外,从下方有一个加写锁的操作,就是为了避免channel还在发送消息时,这边突然关闭channel,这样会导致报错。

public static void removeChannel(Channel channel) {        try {            logger.warn("channel will be remove, address is :{}", NettyUtil.parseChannelRemoteAddr(channel));            //加上读写锁保证移除channel时,避免channel关闭时,还有别的线程对其操作,造成错误            rwLock.writeLock().lock();            channel.close();            UserInfo userInfo = userInfos.get(channel);            if (userInfo != null) {                if (userInfo.isAuth()) {                    offlineInfoTransmitStatic.unregisterPull(channel);                    // 减去一个认证用户                    userCount.decrementAndGet();                }                userInfos.remove(channel);            }        } finally {            rwLock.writeLock().unlock();        }    }

为了无缝切换使用rabbitmq、rocketmq、activemq、不使用中间件存储和转发聊天消息这4种状态,定义如下4个接口。依次是发送单聊消息、群聊消息、客户端启动接收消息、客户端下线不接收消息。

public interface OfflineInfoTransmit {    void pushP2P(Integer userId, String message);    void pushGroup(String groupNumber, String message);    void registerPull(Channel channel);    void unregisterPull(Channel channel);}

其中,如何使用rabbitmq、rocketmq、activemq三种中间件中的一种来存储和转发聊天消息,它的处理流程如下:

  1. 单聊的模型参考线程池的模型,如果用户在线,直接通过channel发送给用户。如果用户离线,则发往中间件存储,下次用户上线时直接从中间件拉取消息。这样做对比所有消息的发送都通过中间件来转的好处是提升了性能
  2. 群聊则是完全通过中间件来转发消息,消息发送中间件,客户端从中间件接取消息。如果仍像单聊那样操作,在线用户直接通过channel发送,操作过于繁琐,要判断这个群组的哪些用户是否在线
  3. 如果用户在线就注册消费者,从中间件接取消息。否则,就断开消费者,消息保留在中间件中,以便客户端下次上线时拉取。这样就实现了离线消息的接收。
  4. 不管使用哪种中间件或使用不使用中间件,它的处理流程都遵循上面的3个要求,就能无缝切换上方的4种方法来存储和转发消息。需要哪种方法开启相应注解即可。
12325a6097a257ee7abb7f136a400921.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值