在上一篇 SignalR 文章中,演示了如何通过 SignalR 实现了简单的聊天室功能;本着简洁就是美的原则,这一篇我们也来聊聊在 SignalR 中的用户和组的概念,理解这些基础知识有助于更好的开发基于 SignalR 的应用,通过对用户和分组的理解,进一步扩展出对用户和分组的管理,以及消息推送的各种方式,为全面接入 SignalR 做准备。

1. 用户

在 SignalR 中,用户表示连接,一个用户代表一个连接,一个“系统用户”可以创建多个连接身份,通过函数集线器,可以给一个用户的所有连接发送消息;比如一个“系统用户”拥有多个连接,这些连接分别是 Web连接、AndroId手机客户端连接,IOS手机客户端连接、或者其它客户端连接,“系统用户”分别登录了这些客户端,同时创建了多个连接;默认情况下这些连接都通过 ClaimTypes.NameIdentifier 在 ClaimsPrincipal 于用户标识进行关联。

** 注意:用户标识符是区分大小写的,为了实现一个客户多个连接,本例还简单实现了一个基于 ClaimsIdentity 登录接口,算是意外惊喜。

1.1 用户连接管理

为了直观的观察到用户是可以拥有多连接的,需要建立一个本地静态对象,用于存储用户连接

public class WeChatHub : Hub
{
public Dictionary<string, List<string>> UserList { get; set; } = new Dictionary<string, List<string>>(); public void Send(ChatMessage body)
{
Clients.All.SendAsync("Recv", body);
} public override Task OnConnectedAsync()
{
var userName = this.Context.User.Identity.Name;
var connectionId = this.Context.ConnectionId;
if (!UserList.ContainsKey(userName))
{
UserList[userName] = new List<string>();
UserList[userName].Add(connectionId);
}
else if (!UserList[userName].Contains(connectionId))
{
UserList[userName].Add(connectionId);
}
Console.WriteLine("哇,有人进来了:{0},{1},{2}", this.Context.UserIdentifier, this.Context.User.Identity.Name, this.Context.ConnectionId);
return base.OnConnectedAsync();
} public override Task OnDisconnectedAsync(Exception exception)
{
var userName = this.Context.User.Identity.Name;
var connectionId = this.Context.ConnectionId;
if (UserList.ContainsKey(userName))
{
if (UserList[userName].Contains(connectionId))
{
UserList[userName].Remove(connectionId);
}
} Console.WriteLine("靠,有人跑路了:{0}", this.Context.ConnectionId);
return base.OnDisconnectedAsync(exception);
}
}

上面的代码包含了一个内部成员 UserList,用于存储用户的每个连接,在用户进行 SignalR 连接时,将当前连接存储到 UserList 中,当连接断开的时候,将当前连接从 UserList 中删除。这样就实现了一个简单的用户连接管理。

在上面的代码中,当前用户昵称是根据 var userName = this.Context.User.Identity.Name; 这行代码获取的,为了取得这个用户昵称,我们实现了一个简单的 UserIdentity 登录,然后将 User 信息写入到 Cookie 中,最后才可以通过 var userName = this.Context.User.Identity.Name; 获得当前登录用户昵称(熟悉 ID 登录流程的同学应该不会感到陌生,实际上我也很少使用 ID 验证)

1.2 给单个用户发送消息
        [Authorize(Roles = "User")]
[HttpPost("SendToUser")]
public async Task<IActionResult> SendToUser([FromBody] UserInfoViewModel model)
{
ChatMessage message = new ChatMessage()
{
Type = 1,
Content = model.Content,
UserName = model.UserName
}; if (this.chatHub.UserList.ContainsKey(model.UserName))
{
var connections = this.chatHub.UserList[model.UserName].First();
await this.chatHub.Clients.Client(connections).SendAsync("Recv", new object[] { message });
} return Json(new { Code = 0 });
}

在 UserController 中,定义了上面的接口 SendToUser ,客户端传入用户昵称和消息,然后服务端就会去根据 ChatHub.UserList 成员查找目标用户的连接信息,最后,通过 SendAsync 将消息推送到目标客户端连接中。

2. 分组

分组的概念类似于聊天室,每个房间就是一个独立的分组,用户可以选择加入 A 房间,也可以选择加入 B 房间,如果业务允许,一个用户还可以加入多个分组(房间),通过使用分组对用户进行管理,可以实现一个或者多个聊天房间,用户可以加入分组,也可以将用户从分组中删除(类似离开房间),这里的用户并发真正意义上的“系统用户”,而是指系统用户创建的那些 SignalR连接。

** 注意:当连接断开后重新发起连接的时候,SignalR 不会保留组成员身份,必须重新加入分组。

下面的代码演示了如何对分组进行操作,要对分组进行操作,主要包含三个方面:

2.1 加入分组
    public async Task AddToGroupAsync(string groupName)
{
await Groups.AddToGroupAsync(this.Context.ConnectionId, groupName);
}
2.2 离开分组
        public async Task RemoveFromGroupAsync(string groupName)
{
await Groups.RemoveFromGroupAsync(this.Context.ConnectionId, groupName);
}
2.3 发送消息到指定分组
        public async Task SendToGroupAsync(string groupName, ChatMessage message)
{
await Clients.Group(groupName).SendAsync(groupName, new object[] { message });
}

对分组的操作非常的简单,几乎都是一行代码的事情,不得不说,微软的封装实在是太好了。

3. SignalR的推送消息的其它方式

通过上面对用户和分组的学习,再去扩展学习其它推送消息的方式,就非常的好理解和上手,在 SignalR 内部还有多种推送消息的方式,他们分别是

3.1 All(全站推送)
3.2 Others(全站推送排除自己)
3.3 OthersInGroup(指定分组推送,排除自己)
3.4 AllExcept(除指定列表外的所有人)
3.5 演示代码
        List<string> blackList = new List<string>();
public async Task OtherSendAsync(ChatMessage body)
{
// 给当前连接到 Hub 上的所有连接发送消息,相当于广播
await Clients.All.SendAsync("Recv", body); // 给当前连接对象发送消息
await Clients.Caller.SendAsync("Recv", body); // 给其它所有连接的客户端发送消息,除了当前正在连接的客户端
await Clients.Others.SendAsync("Recv", body); // 查找当前所有连接的客户端(排除自己),如果是已加入此分组,则给他们推送消息
await Clients.OthersInGroup("groupName").SendAsync("Recv", body); // 给除了 blackList(黑名单)之外的所有人发送消息
await Clients.AllExcept(blackList).SendAsync("Recv", body);
}

4. 一个简单的示例

本示例代码包含两个简单的界面

4.1 登录

4.2 各种方式发送消息

结束语

最近在做一个开源项目,还处于试用阶段,准备写个使用的 WIKI 出来,看看大家是否感兴趣,此 SingalR 系列只能不定期更新了,抱歉。

演示代码下载

已托管到 GitHub 仓库

https://github.com/lianggx/Examples/tree/master/SignalR/Ron.SignalRLesson2

SignalR 中丰富多彩的消息推送方式的更多相关文章

  1. Asp.net SignalR 实现服务端消息推送到Web端

              之前的文章介绍过Asp.net SignalR,  ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.  今天我 ...

  2. django中实现微信消息推送

    -公众号(不能主动给用户发消息) -认证的公众号:需要营业执照,需要交钱,可以发多篇文章 -未认证的公众号:一天只能发一篇文章 -服务号(微信推送) -需要申请,需要认证 -可以主动给用户推送消息 - ...

  3. 使用SignalR实现服务端消息推送

    概述 这篇文章参考的是Server Broadcast with SignalR 2这篇教程,很不错的一篇教程,如果有兴趣的话可以查看原文,今天记录下来作为一个学习笔记,这样今后翻阅会更方便一点. 这 ...

  4. SignalR web实时同步 消息推送 广播

    源码:https://github.com/SignalR/SignalR demo:http://download.csdn.net/download/qq_21533697/9702791#com ...

  5. APP消息推送:通知和透传

    目前市场上的消息推送方式有两种:通知和透传.什么是透传?透传即是透明传送,即传送网络无论传输业务如何,只负责将需要传送的业务传送到目的节点,同时保证传输的质量即可,而不对传输的业务进行处理.透传消息, ...

  6. 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

    1.前言 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力. 这种在APP处于后台或关闭情况下的消息推送能力,通常在以下场景下非常有用: 1)IM即时通讯 ...

  7. python 全栈开发,Day103(微信消息推送,结算中心业务流程)

    昨日内容回顾 第一部分:考试题(Python基础) 第二部分:路飞相关 1. 是否遇到bug?难解决的技术点?印象深刻的事? - orm操作费劲 - 最开始学习路由系统时候,匹配规则: 答案一: 有, ...

  8. 【js学习】js连接RabbitMQ达到实时消息推送

    js连接RabbitMQ达到实时消息推送 最近在自己捯饬一个网站,有一个功能是需要后端处理完数据把数据发布到MQ中,前端再从MQ中接收数据.但是前端连接MQ又成了一个问题,在网上搜了下资料,点进去一篇 ...

  9. WinForm中 Asp.Net Signalr消息推送测试实例

    p{ text-align:center; } blockquote > p > span{ text-align:center; font-size: 18px; color: #ff0 ...

随机推荐

  1. CentOS6系列系统启动常见故障排查与解决方法

    情景一.内核文件损坏 /boot/vmlinuz-2.6.32-642.el6.x86_64 内核文件 1.故障现象 2.解决方法:挂载光盘,进入rescue(救援)模式 3.选择--English- ...

  2. Java基础:Java虚拟机(JVM)

    当我们第一次学习Java时这些原理上的东西就会被提到,但是很少有真正去学习.今天开始从头过一遍Java,打算从JVM开始. 1. JVM是什么 2. JRE和JDK 3. JVM结构 3.1. 程序计 ...

  3. mysql 存储引擎简介

    几个常用存储引擎的特点 下面我们重点介绍几种常用的存储引擎并对比各个存储引擎之间的区别和推荐使用方式. 特点 Myisam BDB Memory InnoDB Archive 存储限制 没有 没有 有 ...

  4. SSM博客登录注册

    我的博客采用的是 spring+springmvc+mybatis框架,用maven和git管理项目,之后的其他功能还有待进一步的学习. 首先新建一个maven项目,我的项目组成大概就这样, 建立好项 ...

  5. 升讯威微信营销系统开发实践:(4)源代码结构说明 与 安装部署说明( 完整开源于 Github)

    GitHub:https://github.com/iccb1013/Sheng.WeixinConstruction因为个人精力时间有限,不会再对现有代码进行更新维护,不过微信接口比较稳定,经测试至 ...

  6. day12 EL 表达式和国际化开发

    day12 EL 表达式和国际化开发 1. EL(Expression Language) 表达式简介 1.1 执行运算 1.2 获取web开发常用对象(el 中定义了11个隐式对象) 1.3 使用 ...

  7. 并发库应用之十二 & 常用集合问题汇总

    1. List遍历时修改报错 别的先什么都不说,直接上代码看看就知道了: public class ListTest { public static void main(String[] args) ...

  8. 十八、Hadoop学记笔记————Hbase架构

    Hbase结构图: Client,Zookeeper,Hmaster和HRegionServer相互交互协调,各个组件作用如下: 这几个组件在实际使用过程中操作如下所示: Region定位,先读取zo ...

  9. TGI

    淘宝的很多分析会用到TGI这个指标,但是是如何计算的以及该如何理解和应用这个指标?TGI:即Target Group Index(目标群体指数)TGI指数= [目标群体中具有某一特征的群体所占比例/总 ...

  10. toFixed()一不小心踩了一个坑

    toFixed,多么简单的一个函数,昨天突发奇想做两道算法题练练手.结果,踩到了一个从未遇到的坑! \n 简单来讲是要对输入的很多组数据,自己写一个函数做个处理,把每次函数处理的结果要相加求和.最后输 ...