在后台主机中托管SignalR服务并广播心跳包
什么是后台主机
在之前的 Asp.NETCore 轻松学系列中,曾经介绍过一个轻量级服务主机 IHostedService ,利用 IHostedService 可以轻松的实现一个系统级别的后台服务,该服务跟随系统启动和停止;同时,其使用异步加载和兼容注入的特性,可以很好的实现业务的扩展和隔离。
IHostedService 有一个默认的实现基类 Microsoft.Extensions.Hosting.BackgroundService,我们仅需要继承 BackgroundService 即可实现后台主机。
本文主要目的在于实现一个后台心跳广播包,所有连接到 SignalR 的客户端,通过订阅心跳包广播频道,能够自动收到服务器发送的心跳广播
广播协议定义
public interface IHeartbeat
{
Task HeartbeatAsync(int data);
}
上面定义 了一个接口 IHeartbeat,该接口有一个异步的方法 HeartbeatAsync,主要就是心跳的定义,先不管它怎么使用,我们继续往下
定义一个泛型的 Hub
public class WeChatHub : Hub<IHeartbeat>
{
public void Send(ChatMessage body)
{
Clients.All.RecvAsync(body);
}
public override Task OnConnectedAsync()
{
Console.WriteLine("游客[{0}]进入了聊天室", this.Context.ConnectionId);
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
Console.WriteLine("游客[{0}]离开了聊天室", this.Context.ConnectionId);
return base.OnDisconnectedAsync(exception);
}
}
上面定义了一个SignalR通信管理对象 WeChatHub ,其继承字泛型的 Hub,其中,泛型类型指定为 IHeartbeat 接口,这里的泛型即表示 SignalR 的客户端,其代表一种通信协议包,SignalR 的客户端(各种类型的)如果希望收到 IHeartbeat 定义的消息(方法实现),必须侦听 IHeartbeat 的定义(方法名称和参数)
上面的这段话比较绕口,其实我也觉得不太好理解,简单来说就是客户端要侦听一个和 SignalR 服务端定义的相同的频道,才可以收到广播。
定义后台服务主机
在定义好 SignalR 的通信协议后,接下来要做的就是实现一个后台服务主机,也就是 IHostedService 的实现。根据 Asp.Net Core 轻松学-基于微服务的后台任务调度管理器 中的提示,我们不需要实现这个接口,只需要继承 Microsoft.Extensions.Hosting.BackgroundService 即可
实现代码
public class WeChatHubWorker : BackgroundService
{
private readonly IHubContext<WeChatHub, IHeartbeat> heartbeat;
public WeChatHubWorker(IHubContext<WeChatHub, IHeartbeat> heartbeat)
{
this.heartbeat = heartbeat;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await this.heartbeat.Clients.All.HeartbeatAsync(0);
await Task.Delay(3000);
Console.WriteLine("heartbeat");
}
}
}
上面的代码比较简单,首先定义了 IHubContext<WeChatHub, IHeartbeat> 对象 heartbeat,然后在构造函数中通过注入的方式将其实例化,紧接着在 ExecuteAsync(CancellationToken stoppingToken) 方法中,执行了一个无限循环的操作,每 3000 毫秒给所有 SignalR 客户端发送一个内容为 0 的心跳包。
服务注入
实现了后台主机后,需要将其注入到 Asp.NETCore 的管道中
// 添加服务主机随主机启动
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddHostedService<WeChatHubWorker>();
...
}
// 配置 SignalR 侦听的 Uri 地址
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseSignalR(routes =>
{
routes.MapHub<WeChatHub>("/wechatHub");
});
...
}
通过服务注入,我们就完成了服务端的实现,下面看看 JavaScript 的实现。
JavaScript 客户端的实现
var connection = new signalR.HubConnectionBuilder()
.withUrl("/wechatHub")
.build();
connection.on("RecvAsync", function (data) {
var li = document.createElement("li");
li = $(li).text(data.userName + ":" + data.content);
$("#msgList").append(li);
});
connection.on("HeartbeatAsync", (data) => {
console.log(data);
});
connection.start()
.then(function () {
console.log("客户端已连接");
}).catch(function (err) {
console.log(err);
});
上面的代码,如果有看过前两章的同学,应该是非常熟悉的,这里就不多解释了;但是,由于本次 SignalR 服务端的 Hub 实现不太一样,所以,这里还是要解释一下。
上面的代码分别侦听了两个通道 connection.on("RecvAsync",...) 和 connection.on("HeartbeatAsync",...) ,这两个通道对应服务端的 IHeartbeat 的定义的成员名称,然后在 Callback 中的参数,也需要和 IHeartbeat 定义的一样,保证可以完整接收服务端推送的消息。
- RecvAsync 通道用来接收和发送客户端的聊天消息(主动/被动)
- HeartbeatAsync 通道用来接收来自服务端推送的心跳广播(被动)
运行演示
运行服务端,分别打开两个客户端,同时观察服务端和客户端的心跳输出

红圈处就是心跳广播的内容:0。
使用两个客户端分别发送聊天消息

红圈处就是聊天消息。
扩展
如果需要开通多个通道的话怎么办呢,聪明的你一定想到了,就是增加 IHeartbeat 的定义,然后在客户端订阅该频道即可。
示例代码下载
https://github.com/lianggx/Examples/tree/master/SignalR/Ron.SignalRLesson3
在后台主机中托管SignalR服务并广播心跳包的更多相关文章
- Azure开发者任务之七:在Azure托管服务中托管WCF服务角色
在一个托管服务中托管一个WCF服务角色和托管一个ASP.Net Web Role基本类似. 在上一篇文章中,我们学习了如何使用WCF Service Web Role. 在本文中,我会对上一篇文章进行 ...
- 腾讯云 TKE Everywhere 特性发布,用户可在自有基础设施中托管 K8s 服务
作者 孔令飞,腾讯云资深工程师,拥有大规模 Kubernetes 集群.微服务的研发和架构经验,目前专注于云原生混合云领域的基础架构开发. 朱翔,腾讯云容器服务高级产品经理,目前负责云原生混合云产品方 ...
- 创建自托管的SignalR服务端
微软官方例子地址:http://www.asp.net/signalr/overview/deployment/tutorial-signalr-self-host 1.说明: SignalR服务端可 ...
- SignalR入门之多平台SignalR服务端
之前创建SignalR服务端是基于Web应用程序而言的.那么能不能把SignalR服务端做成控制台应用程序.Winform或windows服务呢? 答案是肯定的. 之前尽管看起来好像是IIS和ASP. ...
- 一、在 ASP.NET Core 中使用 SignalR
一.介绍 SignalR 是一个用于实现实时网站的 Microsoft .NET 库.它使用多种技术来实现服务器与客户端间的双向通信,服务器可以随时将消息推送到连接的客户端. https://docs ...
- Signalr 实现心跳包
项目分析: 一个实时的IM坐席系统,客户端和坐席使用IM通信,客户端使用android和ios的app,坐席使用web. web端可以保留自己的登录状态,但为防止意外情况的发生(如浏览器异常关闭,断网 ...
- IIS 中托管基于TCP绑定的WCF服务
IIS 中托管基于TCP绑定的WCF服务 一.创建一个基于TCP绑定的WCF服务 1.创建一个的简单的服务具体代码如下 服务契约定义 namespace SimpleService { // 注意: ...
- windows 服务中托管asp.net core
在windows 服务中托管asp.net core SDK 2.1.300 官方示例 1.添加运行标识符 xml <PropertyGroup> <TargetFramework& ...
- 三十、【C#.Net开发框架】WCFHosting服务主机的利用WCF服务通讯和实现思路
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...
随机推荐
- Nowcoder84D
Nowcoder84D 传送门 很有趣的进制转换题! 如果x满足题意,那么x+k-1一定能符合要求! 因为k-1用k进制表示就是1,-1,1+(-1)=0所以数位之和不变! 用map维护一下前缀和.就 ...
- 寻找DevExpress破解经历之旅
众所周知DevExpress是收费的,但是破解版的也不少,近期公司需要做发票套打的功能让我找个打印工具,我寻思着DevExpress这个软件好像挺不错的,功能强大,看了下价格方面,好吧!2W多呢,市面 ...
- 如何使用php生成唯一ID的4种方法
php生成唯一ID的应用场景非常普遍,如临时缓存文件名称,临时变量,临时安全码等,uniqid()函数基于以微秒计的当前时间,生成一个唯一的 ID.由于生成唯一ID与微秒时间关联,因此ID的唯一性非常 ...
- 浏览器渲染原理笔记 --《How Browser Work》读后总结
综述 之前使用ExtJS时遇到一个问题:为什么依次设置多个组件的可见性界面会卡顿?在了解HTML的dom操作相关内容的时候也好奇这个东西到底是怎么回事,然后尤其搞不懂CSS和Html分管样式和网页结构 ...
- AUTOSAR分层-MCAL辨析
8. AUTOSAR中MCAL虽然包含各种drvier,但毕竟是AL即抽象层,不应包含architecture和device特定的信息.应该只包含模型定义,不包含实现细节. AUTOSAR文档中的 ...
- Python(Django)项目与Apache的管理交互
(开开心心每一天~ ---虫瘾师) Python(Django)项目交给Apache的管理(一) 准备:Django的环境(Python).Apache.Wsgi(必须文件) 首先需要电脑有Pytho ...
- DX11 Without DirectX SDK--05 键盘和鼠标输入
回到 DirectX11--使用Windows SDK来进行开发 提供键鼠输入可以说是一个游戏的必备要素.在这里,我们不使用DirectInput,因为Windws SDK本身就不提供该头文件.这里我 ...
- 管理和安装 chart - 每天5分钟玩转 Docker 容器技术(168)
安装 chart 当我们觉得准备就绪,就可以安装 chart,Helm 支持四种安装方法: 安装仓库中的 chart,例如:helm install stable/nginx 通过 tar 包安装,例 ...
- 几张图帮你理解 docker 基本原理及快速入门
写的非常好的一篇文章,不知道为什么被删除了. 利用Google快照,做个存档. 快照地址:地址 作者地址:青牛 什么是docker Docker 是一个开源项目,诞生于 2013 年初,最初是 do ...
- linux timerfd系列函数总结
网上关于timerfd的文章很多,在这儿归纳总结一下方便以后使用,顺便贴出一个timerfd配合epoll使用的简单例子 一.timerfd系列函数 timerfd是Linux为用户程序提供的一个定时 ...