BindMessageListener

如下代码作为理解入口,安卓、IOS、web在连接成功后才会发起所谓登录,登录时会携带必要信息,例如个人账号唯一标识uid、设备类型deviceId等字段发起登录请求,目前重写的onMessage回调方法中只是对登录逻辑进行处理,若要实现单聊及群聊需要额外拓展参数msgType(信息参数类型),根据信息类型作出相应的逻辑处理,在登录逻辑中:
1.Session session = JSONUtils.fromJson(redisMessage.getBody(), Session.class); String uid = session.getUid(); 获取uid,后面根据uid及设备限定类型过滤筛选出此账号的所有频道(因为一个账号可以在不同终端登录,而同一终端只能一个账号登录)
2.channelList.removeIf(channel -> session.getNid().equals(channel.attr(ChannelAttr.ID).get()));意思是将要通知下线的频道集合中过滤掉本次连接的频道,不然也会通知刚连接上的频道
3.Collection<Channel> 相同账号不同终端的频道都放在此
4.@Resource private SessionGroup sessionGroup;sessionGroup是存放所有频道信息的容器,后续单聊、群聊拓展需要从此理解及开发逻辑

package com.farsunset.cim.component.message;import com.farsunset.cim.entity.Session;
import com.farsunset.cim.sdk.server.constant.ChannelAttr;
import com.farsunset.cim.sdk.server.group.SessionGroup;
import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.util.JSONUtils;
import io.netty.channel.Channel;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;/*** 集群环境下,监控多设备登录情况,控制是否其余终端下线的逻辑*/
@Component
public class BindMessageListener implements MessageListener {private static final String FORCE_OFFLINE_ACTION = "999";private static final String SYSTEM_ID = "0";/*一个账号只能在同一个类型的终端登录如: 多个android或ios不能同时在线一个android或ios可以和web,桌面同时在线*/private final Map<String,String[]> conflictMap = new HashMap<>();@Resourceprivate SessionGroup sessionGroup;public BindMessageListener(){conflictMap.put(Session.CHANNEL_ANDROID,new String[]{Session.CHANNEL_ANDROID,Session.CHANNEL_IOS});conflictMap.put(Session.CHANNEL_IOS,new String[]{Session.CHANNEL_ANDROID,Session.CHANNEL_IOS});conflictMap.put(Session.CHANNEL_WINDOWS,new String[]{Session.CHANNEL_WINDOWS,Session.CHANNEL_WEB,Session.CHANNEL_MAC});conflictMap.put(Session.CHANNEL_WEB,new String[]{Session.CHANNEL_WINDOWS,Session.CHANNEL_WEB,Session.CHANNEL_MAC});conflictMap.put(Session.CHANNEL_MAC,new String[]{Session.CHANNEL_WINDOWS,Session.CHANNEL_WEB,Session.CHANNEL_MAC});}@Overridepublic void onMessage(org.springframework.data.redis.connection.Message redisMessage, byte[] bytes) {Session session = JSONUtils.fromJson(redisMessage.getBody(), Session.class);String uid = session.getUid();String[] conflictChannels = conflictMap.get(session.getChannel());Collection<Channel> channelList = sessionGroup.find(uid,conflictChannels);channelList.removeIf(channel -> session.getNid().equals(channel.attr(ChannelAttr.ID).get()));/** 获取到其他在线的终端连接,提示账号再其他终端登录*/channelList.forEach(channel -> {if (Objects.equals(session.getDeviceId(),channel.attr(ChannelAttr.DEVICE_ID).get())){channel.close();return;}Message message = new Message();message.setAction(FORCE_OFFLINE_ACTION);message.setReceiver(uid);message.setSender(SYSTEM_ID);message.setContent(session.getDeviceName());channel.writeAndFlush(message);channel.close();});}
}

netty即时通讯SDK部分源码

package com.farsunset.cim.sdk.server.group;import com.farsunset.cim.sdk.server.constant.ChannelAttr;
import com.farsunset.cim.sdk.server.model.Message;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Predicate;
import java.util.stream.Collectors;public class SessionGroup extends ConcurrentHashMap<String, Collection<Channel>> {private static final Collection<Channel> EMPTY_LIST = new LinkedList<>();private final transient ChannelFutureListener remover = new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future){future.removeListener(this);remove(future.channel());}};protected String getKey(Channel channel){return channel.attr(ChannelAttr.UID).get();}public void remove(Channel channel){String uid = getKey(channel);if(uid == null){return;}Collection<Channel> collections = getOrDefault(uid,EMPTY_LIST);collections.remove(channel);if (collections.isEmpty()){remove(uid);}}public void add(Channel channel){String uid = getKey(channel);if (uid == null || !channel.isActive()){return;}channel.closeFuture().addListener(remover);Collection<Channel> collections = this.putIfAbsent(uid,new ConcurrentLinkedQueue<>(Collections.singleton(channel)));if (collections != null){collections.add(channel);}if (!channel.isActive()){remove(channel);}}public void write(String key,Message message){find(key).forEach(channel -> channel.writeAndFlush(message));}public void write(String key, Message message, Predicate<Channel> matcher){find(key).stream().filter(matcher).forEach(channel -> channel.writeAndFlush(message));}public void write(String key, Message message, Collection<String> excludedSet){find(key).stream().filter(channel -> excludedSet == null || !excludedSet.contains(channel.attr(ChannelAttr.UID).get())).forEach(channel -> channel.writeAndFlush(message));}public void write(Message message){this.write(message.getReceiver(),message);}public Collection<Channel> find(String key){return this.getOrDefault(key,EMPTY_LIST);}public Collection<Channel> find(String key,String... channel){List<String> channels = Arrays.asList(channel);return find(key).stream().filter(item -> channels.contains(item.attr(ChannelAttr.CHANNEL).get())).collect(Collectors.toList());}
}

安卓发送信息接口

package com.farsunset.cim.http;import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;public interface MessageService {@POST("/send")@FormUrlEncodedCall<Void> send(@Field("sender") String sender,@Field("receiver") String receiver,@Field("action") String action,@Field("content") String content);
}

CIM即时通讯源码初步解析(一款个人推荐的带集群的开源项目)相关推荐

  1. 用于二次开发企业即时通讯源码(C++/MFC)

    用于二次开发企业即时通讯源码(C++/MFC),现在,做一个普通的即时通讯软件不是一件难事,网上有很多很好的这类软件的源代码可以拿来使用.今天就介绍一个我用过,觉得不错的给大家.软件叫 XEIM,中文 ...

  2. GoEasy小程序即时通讯源码 v1.1.0基于GoEasy提供的websocket通讯服务

    介绍: GoEasy小程序即时通讯源码是一个基于GoEasy提供的websocket通讯服务,实现的小程序即时通讯,支持一对一单聊.群聊.会话列表.上下线提醒.历史消息.离线消息,支持发送图片.视频. ...

  3. 即时通讯源码,包含安卓,iOS,H5,MacOS,PC,Java后端

    即时通讯源码,包含安卓,iOS,H5,MacOS,PC,Java后端 YID:391000625261646335酷柒网络技术有限公司

  4. PHP在线客服即时通讯源码

    PHP在线客服即时通讯源码 一款php在线即时通讯客服系统,程序采用thinkphp框架 能在线传输文件图片 合适个人和小型接入 源码介绍 安装环境:linux宝塔,php5.6,mysql5.5或5 ...

  5. 即时通讯源码基IM源码内核开发采用[uniapp]封装技术

    即时通讯源码是基于开源IM源码内核开发的,根据业务需要改造而来.修改和扩展了很多ejaberd不支持的功能.程序实现了一个 XMPP 即时消息客户端.创建此应用程序是为了演示使用XMPP和Ember创 ...

  6. tigase集群配置搭建官方方法-xmpp通讯协议配备tigase集群开发简单省事-哇谷即时通讯IM源码服务-哇谷即时通讯源码

    tigase集群配置搭建官方方法-xmpp通讯协议配备tigase集群开发简单省事-哇谷即时通讯IM源码服务 哇谷即时通讯IM云-即时通讯源码-音视频会议-直播-短视频-企业即时通讯办公-聊天app- ...

  7. 即时通讯源码-即时通讯集群服务免费-通讯百万并发技术-Openfire 的安装配置教程手册-哇谷即时通讯集群方案-哇谷云-哇谷即时通讯源码

    即时通讯源码-即时通讯集群服务免费-通讯百万并发技术-Openfire 的安装配置教程手册-哇谷即时通讯集群方案-哇谷云 1,openfire开发环境配置 很久没有写点东西了.最近很烦心,领导不给力. ...

  8. im即时通讯源码_IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)

    1.引言 在中大型IM系统中,聊天消息的唯一ID生成策略是个很重要的技术点.不夸张的说,聊天消息ID贯穿了整个聊天生命周期的几乎每一个算法.逻辑和过程,ID生成策略的好坏有可能直接决定系统在某些技术点 ...

  9. 即时通讯源码_一对一视频直播系统源码是如何实现即时通讯呢?

    作者/布谷惠泽 来源/山东布谷鸟网络 在这个快速发展的时代,急功近利,心浮气躁成为当代人的共性.大多数人承受着巨大的压力,在这个时代小心翼翼的行走,而一对一直播交友源码的出现,成为人们宣泄压力的新渠道 ...

  10. 鸽哒im即时通讯源码加教程

    介绍: 鸽哒是一款类似于v的即时通讯软件. 独立部署!加密通道!牢牢掌握通讯信息! 1.产品为独立开发,非网上下载不能用的产品! 2.即时聊天软件技术难度大,请不要拿网络其他聊天软件来对比! 3.网络 ...

最新文章

  1. 人脸标记检测:ICCV2019论文解析
  2. PostMessage
  3. stm32 IAP + APP ==双剑合一
  4. mysql cascade|restrict|no action|set null__mysql 外键的几种约束
  5. android 扫描重复文件,Android Gradle在APK META-INF中复制的重复文件
  6. 对POSIX和SystemV消息队列优化:用户态消息队列
  7. fdisk -l查看硬盘分区信息及硬盘分区介绍
  8. hive 修改cluster by算法_spark、hive中窗口函数实现原理复盘
  9. c语言程序设计2试卷答案,《C语言程序设计》试卷2参考答案.doc
  10. 为了躲开违规电动车,我一下子撞电线杆上了
  11. 伪原创方法-学习一下
  12. 375.猜数字大小II
  13. 微信卡死代码 java_微信整人代码有哪些 微信卡死的代码是什么
  14. SQL2008卸载。
  15. 新手微商代理怎么推广产品 微商大咖分享方法值得借鉴
  16. TARA-汽车安全概念
  17. python爬取拉钩网信息
  18. 无涯教程:Node.js - Streams介绍
  19. 数字功放和模拟功放有哪些区别
  20. 镭速(Raysync)文件传输对比Filezilla测试!

热门文章

  1. 【超详细!】【超全面!】计算机二级公共基础知识考点整理
  2. Grasshopper 0.9汉化版下载 【Rhino5.0参数化插件】
  3. java velocity 语法_Velocity初探小结--velocity使用语法详解
  4. windbg中ntsd使用用户态调试器链接到内核调试器的常用技巧
  5. 管理者要会讲的六十八个故事
  6. 万年历节气java代码_[分享]时钟万年历代码,供大家学习GUI
  7. vb导出mysql字段名_VB获取数据库字段名
  8. H5视频播放demo
  9. Task5:第五回:样式色彩秀芳华
  10. Uniapp 移动端调用摄像头扫描二维码或者条形码