在后台主机中托管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 ...
随机推荐
- MySql 动态语句
MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...
- 2017年最适用于WIFI HACK的无线网卡推荐
http://www.freebuf.com/articles/wireless/140065.html 相信很多初次使用Kali Linux来进行无线渗透的小伙伴都曾遇到过一个非常头疼的问题,就是不 ...
- vue UI库iview源码解析(2)
上篇问题 在上篇<iview源码解析(1)>中的index.js 入口文件的源码中有一段代码有点疑惑: /** * 在浏览器环境下默认加载组件 */ // auto install if ...
- Python3实现ICMP远控后门(上)_补充篇
ICMP后门(上)补充篇 前言 在上一篇文章Python3实现ICMP远控后门(上)中,我简要讲解了ICMP协议,以及实现了一个简单的ping功能,在文章发表之后,后台很多朋友留言,说对校验和的计算不 ...
- Python2.7和3.5双版本共存和pip的使用
1. Python2.7和3.5并存 1.1 安装 安装自不必多说,先装2.7,再装3.5. 说下安装的目录:Py3.5和Py2.7默认的安装目录是不一样的,按默认的来就好,不用管. Python2. ...
- 关于HTML5中的sessionStorage和localStorage
需求: 做项目的时大多数情况下我们需要对请求的数据进行多次复用,为了降低请求次数我们需要对请求的数据进行本地存储: 以前用的cooking来存储为本地数据,HTML5后提出sessioStorage. ...
- 洛谷 P1272 解题报告
P1272 重建道路 题目描述 一场可怕的地震后,人们用\(N\)个牲口棚\((1≤N≤150\),编号\(1..N\))重建了农夫\(John\)的牧场.由于人们没有时间建设多余的道路,所以现在从一 ...
- Xamarin.Android 使用AsyncTask提示上传动态
我们有时候会通过WebServices上传数据,如果信息量过大并没有提示,用户会觉得是死机,或是系统崩溃,这时候我们可以用到AsyncTask(异步任务)来提示上传信息,例如:正在上传数据... 这里 ...
- post 和 get 的区别,直指本质
在我们初入java编程之路的时候,面试往往会有一个面试题:get和post的区别是什么?那么你真的知道他们的区别吗?接下来抽丝剥茧,让我们看看get和post到底什么东西,首先从本质的角度看get和p ...
- 导航狗IT周报-2018年05月18日
原文链接:https://www.daohanggou.cn/2018/05/18/it-weekly-8/ DDoS专题 最近Web安全里的一个热点就是包括阮一峰博客在内的多个教育类IT网站被DDo ...