SignalR控制台自托管服务端向web客户端指定用户推送数据,客户端断线重连
一、前言
SignalR是微软推出的开源实时通信框架。其内部使用Web Socket, Server Sent Events 和 Long Polling作为底层传输方式,SignalR会根据客户端和服务端的支持情况,采用回落机制来选择一种传输方式,Web Socket是首选的。在web开发中,SignalR可以很好的解决传统ajax轮询的问题,真正做到实时通信。
二、编码
- 首先创建2个项目,一个控制台项目,一个web项目。控制台项目作为SignalR服务端,web项目作为客户端。

- 先从服务端开始:
安装NuGet包
控制台程序作为宿主实现自托管,需要安装:Microsoft.AspNet.SignalR.SelfHost

添加跨域支持:Microsoft.Owin.Cors

- 服务端SignalRServer.Program代码:
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
namespace SignalRServer
{
class Program
{
static void Main(string[] args)
{
var url = "http://localhost:8019";
using (WebApp.Start(url))
{
Console.WriteLine("SignalR运行:" + url);
Console.WriteLine("输入要发送的消息,用户与消息之间用空格隔开:");
var hub = GlobalHost.ConnectionManager.GetHubContext<CustomHub>();
while (true)
{
var str = Console.ReadLine();
hub.Clients.Client(CustomHub.OnLineUsers[str.Split(' ')[0]]).refreshData(str.Split(' ')[1]);
}
}
}
}
public class CustomHub : Hub
{
//在线用户
public static ConcurrentDictionary<string, string> OnLineUsers = new ConcurrentDictionary<string, string>();
public override Task OnConnected()
{
string clientName = Context.QueryString["clientName"].ToString();
OnLineUsers.AddOrUpdate(clientName, Context.ConnectionId, (key, value) =>
{
return Context.ConnectionId;
});
Console.WriteLine($"{clientName}:{Context.ConnectionId}已连接。");
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
string clientName = Context.QueryString["clientName"].ToString();
string client;
OnLineUsers.TryRemove(clientName, out client);
Console.WriteLine($"{clientName}:{Context.ConnectionId}已断开。");
return base.OnDisconnected(stopCalled);
}
public override Task OnReconnected()
{
string clientName = Context.QueryString["clientName"].ToString();
OnLineUsers.AddOrUpdate(clientName, Context.ConnectionId, (key, value) =>
{
return Context.ConnectionId;
});
Console.WriteLine($"{clientName}:{Context.ConnectionId}已重连。");
return base.OnReconnected();
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
}
以上代码大致就是指定一个url启动SignalR服务,CustomHub中维护了一个在线客户端集合,控制台根据输入的信息发送到对应的客户端...
- 下面是客户端
同样先安装NuGet包
安装Microsoft.AspNet.SignalR.JS

- 创建2个视图User1,User2,用来代表2个不同用户
User1.cshtml代码,支持断线重连:
@{
ViewBag.Title = "Index";
Layout = null;
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script id="signalr_script" src="http://localhost:8019/signalr/hubs"></script>
<script type="text/javascript">
$(function () {
//连接Signalr服务器
signalrInit();
});
//signalr初始化配置
function signalrInit() {
try {
//Set the hubs URL for the connection
$.connection.hub.url = 'http://localhost:8019/signalr';
$.connection.hub.qs = { "clientName": "user1" };
// Declare a proxy to reference the hub.
var chat = $.connection.customHub;
// Create a function that the hub can call to broadcast messages.
chat.client.refreshData = function (message) {
//TODO:收到服务端数据
appendMessage(message);
};
signalrConnection();
$.connection.hub.disconnected(function () {
appendMessage('SignalR连接断开!');
//重连
setTimeout(signalrConnection, 10000);
});
//$.connection.hub.stateChanged(function (change) { console.log(change); });
} catch (e) {
appendMessage("SignalR连接异常" + e);
//重新加载hubs
$.getScript('http://localhost:8019/signalr/hubs');
//重新初始化 断线重连
setTimeout(signalrInit, 10000);
}
}
//signalr连接
function signalrConnection() {
$.connection.hub.start()
.done(function () { appendMessage('SignalR建立连接成功'); })
.fail(function () { appendMessage('SignalR建立连接失败'); });
}
function appendMessage(message) {
$("#box").append("<p>" + message + "</p>");
}
</script>
<h1>User1</h1>
<div id="box">
</div>
User2.cshtml代码:
@{
ViewBag.Title = "Index";
Layout = null;
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script id="signalr_script" src="http://localhost:8019/signalr/hubs"></script>
<script type="text/javascript">
$(function () {
//连接Signalr服务器
signalrInit();
});
//signalr初始化配置
function signalrInit() {
try {
//Set the hubs URL for the connection
$.connection.hub.url = 'http://localhost:8019/signalr';
$.connection.hub.qs = { "clientName": "user2" };
// Declare a proxy to reference the hub.
var chat = $.connection.customHub;
// Create a function that the hub can call to broadcast messages.
chat.client.refreshData = function (message) {
//TODO:收到服务端数据
appendMessage(message);
};
signalrConnection();
$.connection.hub.disconnected(function () {
appendMessage('SignalR连接断开!');
//重连
setTimeout(signalrConnection, 10000);
});
//$.connection.hub.stateChanged(function (change) { console.log(change); });
} catch (e) {
appendMessage("SignalR连接异常" + e);
//重新加载hubs
$.getScript('http://localhost:8019/signalr/hubs');
//重新初始化 断线重连
setTimeout(signalrInit, 10000);
}
}
//signalr连接
function signalrConnection() {
$.connection.hub.start()
.done(function () { appendMessage('SignalR建立连接成功'); })
.fail(function () { appendMessage('SignalR建立连接失败'); });
}
function appendMessage(message) {
$("#box").append("<p>" + message + "</p>");
}
</script>
<h1>User2</h1>
<div id="box">
</div>
三、效果
- 服务端和客户端的代码已完成,现在先运行一下服务端控制台程序。右键编译好的SignalRServer.exe,以管理员身份运行(最好是管理员身份运行,不然可能会报错)。

- 运行客户端,浏览器分别打开User1,User2页面


客户端已经显示连接成功

服务端也显示2个已连接 - 向User1发送消息:

- 向User2发送消息:

四、总结
以上就是SignalR的基本使用。
有一些可能的坑:
1.服务端控制台启动报错:尝试用管理员身份启动
2.服务端启动正常,客户端却无法连接,报错Cannot read property 'client' of undefined:有时候可能是端口的问题,换一个端口试一下
3.程序放到服务器,通过外网IP无法连接:WebApp.Start()尝试使用*号格式:http://*:8019
SignalR控制台自托管服务端向web客户端指定用户推送数据,客户端断线重连的更多相关文章
- 使用SignalR ASP.NET Core来简单实现一个后台实时推送数据给Echarts展示图表的功能
什么是 SignalR ASP.NET Core ASP.NET Core SignalR 是一种开放源代码库,可简化将实时 web 功能添加到应用程序的功能. 实时 web 功能使服务器端代码可以立 ...
- SignalR指定用户推送消息
一.首先,在MVC项目中安装SingalR包(SingalR2.0需要.net4.5以上,VS2010可以安装1.1.3版本,本例为VS2010+SignalR1.1.3). 打开工具-NuGet程序 ...
- SuperSocket主动从服务器端推送数据到客户端
关键字: 主动推送, 推送数据, 客户端推送, 获取Session, 发送数据, 回话快照 通过Session对象发送数据到客户端 前面已经说过,AppSession 代表了一个逻辑的 socke ...
- Asp.net Core3.1+Vue 使用SignalR推送数据
本文就简单使用 往前端页面推送消息 SignalR 是什么 SignalR是一个.NET Core/.NET Framework的开源实时框架. SignalR的可使用Web Socket, Serv ...
- 使用Pushlet将消息从服务器端推送到客户端
使用Pushlet来实现服务器端向客户端推送信息 1. 实现方式: 有两种实现方式: 1. 通过配置文件来实现定时的从服务器端向客户端推送信息 2. 通过API主动 ...
- ASP.NET SignalR 系列(四)之指定对象推送
在上一章讲到了广播推送,即所有订阅的用户都能收到,这种适合于信息广播. 接下来介绍如何给指定的对象推送 在讲这个之前先说明一下连接创建的基础知识 1.每个页面与服务端创建连接并启动时,这时服务端会产生 ...
- 利用Ajax+MSMQ(消息队列)+WebService实现服务器端向客户端的信息推送
需求: 每当数据库有数据更新时,推送到客户端 软需求: 1.服务器资源有限,要求资源占用尽可能小: 2.项目可控,不许调用第三方不可信不稳定的方法. 已有事例: 1.58到家采用的方法是TCP的长连接 ...
- C#服务端通过Socket推送数据到Android端App中
需求: 描述:实时在客户端上获取到哪些款需要补货. 要求: 后台需要使用c#,并且哪些需要补货的逻辑写在公司框架内,客户端采用PDA(即Android客户端 版本4.4) . 用户打开了补货通知页面时 ...
- DP使用GUI推送WIN客户端是报110:1022错误的解决办法
在使用GUI推送WIN客户端时,输入用户名和密码后报错: [Critical 110::1022] Cannot connect to the SCM (Service Control Manage ...
随机推荐
- 12个让您震撼的Linux终端命令
以下快捷键很有用,可以节省你的时间: CTRL+U: 从光标处删除文本直到行首. CTRL+K: 从光标处删除文本直到行尾. CTRL+Y: 粘贴文本. CTRL+E: 将光标移动到行尾. CTRL+ ...
- Java子父类间静态代码块、非静态代码块、构造方法的执行顺序
子类A继承父类B,A a=new A(); 正确的执行顺序是:父类B静态代码块->子类A静态代码块->父类B非静态代码块->父类B构造函数->子类A非静态代码块->子类A ...
- Linux系统rabbitmq安装
rabbitmq消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,由消息系统来确保消息的可靠传递.消息发布者只管把消息发布到 MQ 中而不用管谁来取,消息使用者只管 ...
- .NetCore对接各大财务软件凭证API——用友系列(1)
一.前言 今天,我们转战用友系列的第一个产品---T+/Tplus.前两篇文章讲解分享的都是金蝶的产品,因为本身公司牵涉的业务有限,后续有金蝶其他产品的API对接业务时,会继续来分享经验. T+的AP ...
- mysql小白系列_04 binlog(未完)
mysql打开.查看.清理binlog 1.开启日志 log_bin=/var/lib/mysql/mysql-bin mysql> show variables like '%log_bin% ...
- js中获取 table节点各tr及td的内容方法
js中获取 table节点各tr及td的内容方法 分类: java基础2013-10-12 17:54 1055人阅读 评论(0) 收藏 举报 <table id="tb1" ...
- Fabric进阶(三)—— 使用SDK动态增加组织
在fabric网络运行过程中动态追加新的组织是相当复杂的,网上的资料也十分匮乏,大多是基于first-network这样的简单示例,而且是使用启动cli容器的方法来增加组织,几乎没有针对实际应用的解决 ...
- jsonp跨域封装
一.什么是同源政策? 同源策略是指在Web浏览器中,允许某个网页脚本访问另一个网页的数据,但前提是这两个网页必须有相同的URI.主机名和端口号,一旦两个网站满足上述条件,这两个网站就被认定为具有相同来 ...
- vs code插件自动压缩 min.css
我们在进行相应的项目书写的时候,有些需要把scss 和 css 进行 压缩成 min.css 便于更好的使用 在这里强调一下 scss 后来才慢慢接触到这个语言的 感觉的确实懂得明白了之后 好用而且 ...
- thinkphp路由简介和设置使用
use think\Route; //静态路由 Route::rule('/', 'index/index/index'); Route::rule('test', 'index/index/test ...