- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章SignalR中丰富多彩的消息推送方式的实现代码由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
在上一篇 SignalR 文章中,演示了如何通过 SignalR 实现了简单的聊天室功能;本着简洁就是美的原则,这一篇我们也来聊聊在 SignalR 中的用户和组的概念,理解这些基础知识有助于更好的开发基于 SignalR 的应用,通过对用户和分组的理解,进一步扩展出对用户和分组的管理,以及消息推送的各种方式,为全面接入 SignalR 做准备.
1. 用户 。
在 SignalR 中,用户表示连接,一个用户代表一个连接,一个“系统用户”可以创建多个连接身份,通过函数集线器,可以给一个用户的所有连接发送消息;比如一个“系统用户”拥有多个连接,这些连接分别是 Web连接、AndroId手机客户端连接,IOS手机客户端连接、或者其它客户端连接,“系统用户”分别登录了这些客户端,同时创建了多个连接;默认情况下这些连接都通过 ClaimTypes.NameIdentifier 在 ClaimsPrincipal 于用户标识进行关联.
** 注意:用户标识符是区分大小写的,为了实现一个客户多个连接,本例还简单实现了一个基于 ClaimsIdentity 登录接口,算是意外惊喜.
1.1 用户连接管理 。
为了直观的观察到用户是可以拥有多连接的,需要建立一个本地静态对象,用于存储用户连接 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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 给单个用户发送消息 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
[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 加入分组 。
1
2
3
4
|
public
async Task AddToGroupAsync(
string
groupName)
{
await Groups.AddToGroupAsync(
this
.Context.ConnectionId, groupName);
}
|
2.2 离开分组 。
1
2
3
4
|
public
async Task RemoveFromGroupAsync(
string
groupName)
{
await Groups.RemoveFromGroupAsync(
this
.Context.ConnectionId, groupName);
}
|
2.3 发送消息到指定分组 。
1
2
3
4
|
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 演示代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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 。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:http://www.cnblogs.com/viter/p/10638331.html 。
最后此篇关于SignalR中丰富多彩的消息推送方式的实现代码的文章就讲到这里了,如果你想了解更多关于SignalR中丰富多彩的消息推送方式的实现代码的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我一直在阅读有关汇编函数的内容,但对于是使用进入和退出还是仅使用调用/返回指令来快速执行,我感到很困惑。一种方式快而另一种方式更小吗?例如,在不内联函数的情况下,在汇编中执行此操作的最快(stdcal
我正在处理一个元组列表,如下所示: res = [('stori', 'JJ'), ('man', 'NN'), ('unnatur', 'JJ'), ('feel', 'NN'), ('pig',
最近我一直在做很多网络或 IO 绑定(bind)操作,使用线程有助于加快代码速度。我注意到我一直在一遍又一遍地编写这样的代码: threads = [] for machine, user, data
假设我有一个名为 user_stats 的资源,其中包含用户拥有的帖子、评论、喜欢和关注者的数量。是否有一种 RESTful 方式只询问该统计数据的一部分(即,对于 user_stats/3,请告诉我
我有一个简单的 api,它的工作原理是这样的: 用户创建一个请求 ( POST /requests ) 另一个用户检索所有请求 ( GET /requests ) 然后向请求添加报价 ( POST /
考虑以下 CDK Python 中的示例(对于这个问题,不需要 AWS 知识,这应该对基本上任何构建器模式都有效,我只是在这个示例中使用 CDK,因为我使用这个库遇到了这个问题。): from aws
Scala 中管理对象池的首选方法是什么? 我需要单线程创建和删除大规模对象(不需要同步)。在 C++ 中,我使用了静态对象数组。 在 Scala 中处理它的惯用和有效方法是什么? 最佳答案 我会把它
我有一个带有一些内置方法的类。这是该类的抽象示例: class Foo: def __init__(self): self.a = 0 self.b = 0
返回和检查方法执行的 Pythonic 方式 我目前在 python 代码中使用 golang 编码风格,决定移动 pythonic 方式 例子: import sys from typing imp
我正在开发一个 RESTful API。其中一个 URL 允许调用者通过 id 请求特定人员的记录。 返回该 id 不存在的记录的常规值是什么?服务器是否应该发回一个空对象或者一个 404,或者其他什
我正在使用 pathlib.Path() 检查文件是否存在,并使用 rasterio 将其作为图像打开. filename = pathlib.Path("./my_file-name.tif") 但
我正在寻找一种 Pythonic 方式来从列表和字典创建嵌套字典。以下两个语句产生相同的结果: a = [3, 4] b = {'a': 1, 'b': 2} c = dict(zip(b, a))
我有一个正在操裁剪理设备的脚本。设备有时会发生物理故障,当它发生时,我想重置设备并继续执行脚本。我有这个: while True: do_device_control() device
做组合别名的最pythonic和正确的方法是什么? 这是一个假设的场景: class House: def cleanup(self, arg1, arg2, kwarg1=False):
我正在开发一个小型客户端服务器程序来收集订单。我想以“REST(ful)方式”来做到这一点。 我想做的是: 收集所有订单行(产品和数量)并将完整订单发送到服务器 目前我看到有两种选择: 将每个订单行发
我知道在 Groovy 中您可以使用字符串调用类/对象上的方法。例如: Foo."get"(1) /* or */ String meth = "get" Foo."$meth"(1) 有没有办法
在 ECMAScript6 中,您可以使用扩展运算符来解构这样的对象 const {a, ...rest} = obj; 它将 obj 浅拷贝到 rest,不带属性 a。 有没有一种干净的方法可以在
我有几个函数返回数字或None。我希望我的包装函数返回第一个不是 None 的结果。除了下面的方法之外,还有其他方法吗? def func1(): return None def func2(
假设我想设计一个 REST api 来讨论歌曲、专辑和艺术家(实际上我就是这样做的,就像我之前的 1312414 个人一样)。 歌曲资源始终与其所属专辑相关联。相反,专辑资源与其包含的所有歌曲相关联。
这是我认为必须经常出现的问题,但我一直无法找到一个好的解决方案。假设我有一个函数,它可以作为参数传递一个开放资源(如文件或数据库连接对象),或者需要自己创建一个。如果函数需要自己打开文件,最佳实践通常
我是一名优秀的程序员,十分优秀!