前言
上篇的预告好像是“聊天室的小细节,你都注意到了吗?”。今天也是为那篇做铺垫吧。之前的版本有好多问题,比如:当前登录用户是否合法问题,userid参数如果随便传后台没有验证。还有一个致命的问题,用户AB都在线,但是如果A没有打开B的窗口或者B没有打开A的窗口,那么发消息,对方是收不到的。因为他们没有进入到同一个组里面。本篇讲述了一些Redis的东西。由于项目本身就是为了学习和练习一些东西。所以,Redis并不是我的强项,只不过随便研究研究,具体专业的用法我也不太会。还在学习中。。。
实现思路
首先,我采用了Redis中的哈希表结构来存储用户的在线信息。如下图所示:key代表userid,value是用户的connectionid。
是不是很简单,那么存储这些数据有什么好处呢,
1.我们可以统计多少在线用户
2.配合前端界面,实现某个好友是否在线
3.判断好友是否在线在决定是否像该好友推送消息(不在线的话,直接存储离线消息就可以)
4.解决前言中存在的问题。对于这个问题详细解释一下,比如A给B发消息,A点击打开了B的窗口,现在A已经加入到组AB中。但是B不在组AB中,所以,B收不到本组的消息。假如A打开B窗口的时候,判断一下A是否在线,如果A在线,那么将A加入到AB组中,也就是多了一步 A=》Group的操作。这样的话,就解决了AB不同组导致收不到消息的问题。详细看下图:
实现细节
我们只要在Hub代码中的建立连接,失去连接,重新连接的方法中添加对当前用户的操作逻辑就可以。
/// <summary>
/// 获取当前用户信息
/// </summary>
private OnlineUser CurrentOnlineUser
{
get
{
return new OnlineUser
{
connectionid = CurrentConnectId,
userid = CurrentUserId
};
}
}
/// <summary>
/// 建立连接
/// </summary>
/// <returns></returns>
public override Task OnConnected()
{
//将当前用户添加到redis在线用户缓存中
LayIMCache.Instance.OperateOnlineUser(CurrentOnlineUser);
return Clients.Caller.receiveMessage("连接成功");
}
/// <summary>
/// 失去连接
/// </summary>
/// <param name="stopCalled"></param>
/// <returns></returns>
public override Task OnDisconnected(bool stopCalled)
{
//将当前用户从在线用户列表中剔除
LayIMCache.Instance.OperateOnlineUser(CurrentOnlineUser, isDelete: true);
return Clients.Caller.receiveMessage("失去连接");
} /// <summary>
/// 重新连接
/// </summary>
/// <returns></returns>
public override Task OnReconnected()
{
//将当前用户添加到redis在线用户缓存中
LayIMCache.Instance.OperateOnlineUser(CurrentOnlineUser);
return Clients.Caller.receiveMessage("重新连接");
}
这里我用的.NET客户端是 StackExchange.Redis.Extensions.Core ,他其实是在 StackExchange.Redis 的基础上有一层封装。用起来更方便一些,喜欢直接用 StackExchange.Redis 的也没问题。
详细代码如下:
static NewtonsoftSerializer serializer = new NewtonsoftSerializer();
StackExchangeRedisCacheClient cacheClient = new StackExchangeRedisCacheClient(serializer);
#region 在线用户处理
public void OperateOnlineUser(OnlineUser user, bool isDelete = false)
{
if (isDelete)
{
cacheClient.HashDelete(LayIMConst.LayIM_All_OnlineUsers, user.userid);
}
else
{
cacheClient.HashSetAsync(LayIMConst.LayIM_All_OnlineUsers, user.userid, user.connectionid);
}
}
#endregion
当我们刷新页面的时候,会先调用 OnDisconnected 方法,在调用 OnConnected 方法。不过,HashSet方法如果是同一个key,可以覆盖其值。
本篇就到这里了,界面上没有改动,只不过增加了一些基于redis缓存的逻辑。
GitHub:https://github.com/fanpan26/LayIM_NetClient 喜欢的话给一个star吧,谢谢啦。
交流群:145322742
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(八) 之 用 Redis 实现用户在线离线状态消息处理的更多相关文章
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室 实战系列
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言 http://www.cnblogs.com/panzi/p/5742089.html ASP.NET S ...
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十二) 代码重构使用反射工厂解耦(一)缓存切换
前言 上一篇中,我们用了反射工厂来解除BLL和UI层耦合的问题.当然那是最简单的解决方法,再复杂一点的程序可能思路相同,但是在编程细节中需要考虑的就更多了,比如今天我在重构过程中遇到的问题.也是接下来 ...
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言
前端时间听一个技术朋友说 LayIM 2.0 发布了,听到这个消息抓紧去官网看了一下.(http://layim.layui.com/)哎呀呀,还要购买授权[大家支持一下哦],果断买了企业版,喜欢钻研 ...
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取)
大家好,本篇是接上一篇 ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言 ASP.NET SignalR WebIM系列第二篇.本篇会带领大家将 LayIM ...
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。
上篇:ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取) 上一篇我们已经完成了初步界面的搭建工作,本篇将介绍IM的核心内容 ...
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(三) 之 实现单聊,群聊,发送图片,文件。
上篇讲解了如何搭建聊天服务器,以及客户端js怎么和layui的语法配合.服务器已经连接上了,那么聊天还会远吗? 进入正题,正如上一篇提到的我们用 Client.Group(groupId)的方法向客户 ...
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(四) 之 用户搜索(Elasticsearch),加好友流程(1)。
前面几篇基本已经实现了大部分即时通讯功能:聊天,群聊,发送文件,图片,消息.不过这些业务都是比较粗犷的.下面我们就把业务细化,之前用的是死数据,那我们就从加好友开始吧.加好友,首先你得知道你要加谁.L ...
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(五) 之 加好友,加群流程,消息管理和即时消息提示的实现
前言 前前一篇留了个小问题,在上一篇中忘了写了,就是关于LayIM已经封装好的上传文件或者图片的问题.对接好接口之后,如果上传速度慢,界面就会出现假死情况,虽然文件正在上传.于是我就简单做了个图标替代 ...
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(六) 之 Layim源码改造右键菜单--好友、组管理功能的实现。
前言 上一篇中讲解了加好友的流程,本篇将介绍好友管理,群组管理的右键菜单功能.当然由于菜单项目太多,都实现也得花费时间.只讲解一下我是如何从不知道怎么实现右键菜单到会自定义菜单的一个过程.另外呢,针对 ...
-
ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(七) 之 历史记录查询(时间,关键字,图片,文件),关键字高亮显示。
前言 上一篇讲解了如何自定义右键菜单,都是前端的内容,本篇内容就一个:查询.聊天历史纪录查询,在之前介绍查找好友的那篇博客里已经提到过 Elasticsearch,今天它又要上场了.对于Elastic ...
随机推荐
-
javascript基础语法——表达式
× 目录 [1]原始表达式 [2]复杂表达式 前面的话 一般地,关于javascript基础语法,人们听得比较多的术语是操作符和语句.但是,其实还有一个术语经常使用,却很少被提到,这就是javascr ...
-
Linux密码更改
男孩儿的灰色 QQ:936779899 2014.2.9 1. 进入单用户模式 2. 编辑passwd文件,删除X 3. 然后保存推出并编辑shadow文件 4. 删除标色部分,其他保持不变 5. 最 ...
-
IOS--- NavigationBar标题按钮
A.NavigationBar标题按钮 1.需求 在“首页”的导航栏中部设置一个“首页”文字+箭头按钮 统一设置样式 根据实际文本长度调整宽度 消除系统自带的点击高亮效果 点击按钮,箭头上下颠倒 gi ...
-
从spark架构中透视job
本博文的主要内容如下: 1.通过案例观察Spark架构 2.手动绘制Spark内部架构 3.Spark Job的逻辑视图解析 4.Spark Job的物理视图解析 1.通过案例观察Spark架构 sp ...
-
Template 使用注意问题和范例
1. 基本定义 模板是 2. 分类 2.1 函数模板 (1) 作用: 函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计. (2)申明方法: template ...
-
python 集合去重
data = set() data.clear() data.add('qq1') data.add('qq2') data.add('qq3') data.add('qq4') data.add(' ...
-
JavaScript 之 BOM
BOM BOM(Bowser Object Model) 浏览器对象模型 提供了独立于页面内容而与浏览器就行交互的对象,核心对象是window. (BOM 无标准支持) Navigator 浏览器 ...
-
Oracle - 数据库巡检脚本
分享一个oracle数据库巡检脚本,欢迎大家使用,希望大家在用的过程中发现脚本中的错误并提出改进意见. -- 数据库巡检脚本 -- 版本号2.1 -- 该脚本仅对数据库的做一个初步的巡检,具体的优化方 ...
-
Log4j 把不同包的日志打印到不同位置
如果需要将不同的日志打印到不同的地方,则需要定义不同的Appender,然后定义每一个 Appender的日志级别.打印形式.输出位置! 配置log4j.properties文件如下: ####### ...
-
Spring Boot 更换 Banner
Spring 启动时,会有一个Banner图案,这个图案是可以更换的 . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ ...