SignalR介绍

SignalR介绍来源于微软文档,不过多解释。https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction?view=aspnetcore-2.1

ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程。 实时 Web 功能使服务器端代码能够即时将内容推送到客户端。

SignalR 的适用对象:

  • 需要来自服务器的高频率更新的应用。 例如:游戏、社交网络、投票、拍卖、地图和 GPS 应用。
  • 仪表板和监视应用。 示例包括公司仪表板、销售状态即时更新或行程警示。
  • 协作应用。 协作应用的示例包括白板应用和团队会议软件。
  • 需要通知的应用。 社交网络、电子邮件、聊天、游戏、行程警示以及许多其他应用都使用通知。

以下是 ASP.NET Core SignalR 的一些功能:

  • 自动管理连接。
  • 同时向所有连接的客户端发送消息。 例如,聊天室。
  • 将消息发送到特定的客户端或客户端组。
  • 扩展以处理增加的流量。

以上是SignalR介绍,除了以上说明外还有如下优点:

  • 它可支持各个平台通信。只要可以使用websocket就可以进行连接。
  • 而且进行了大量优化处理,非常方便开发者使用。
  • 拥有自由可扩展性,可通过redis 方式搭建分布式socket通信,支持成千上万人不是梦。
  • 自定义协议,除了json协议外、还支持MessagePack协议。还可以自己定义相关协议进行扩展。
  • 可以用于unity、Layair、白鹭引擎、大数据分析平台等高频率使用消息实时通信器。

SignalR使用

一、  新建项目,新建一个空Asp.net core 网站

二、引用SignalR中间件

1. 创建Hub中间件 HubHelper,及游戏简单处理逻辑类

using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Timers; /// <summary>
/// 消息中心
/// </summary>
public class HubHelper : Hub
{
/// <summary>
/// 游戏逻辑
/// </summary>
static GameLogic gameLogic;
static bool isStart = false; /// <summary>
/// 获取当前用户Id
/// </summary>
/// <param name="data"></param>
public void GetId(Data data)
{
Clients.Caller.SendAsync("GetId", Context.ConnectionId);
}
/// <summary>
/// 获取当前连接所有用户
/// </summary>
/// <param name="data"></param>
public void GetALLUser(Data data)
{
if (gameLogic != null)
Clients.Caller.SendAsync("GetALLUser", gameLogic.list);
}
/// <summary>
/// 用户状态改变
/// </summary>
/// <param name="user">用户信息</param>
public void UpdateSate(UserInfo user)
{
gameLogic.UpdateUserInfo(Context.ConnectionId, user);
}
/// <summary>
/// 用户加入
/// </summary>
/// <param name="data"></param>
public void Join(Data data)
{
if (!isStart)
{
isStart = true;
gameLogic = new GameLogic(this.Clients.All);
}
gameLogic.JoinUser(this.Context.ConnectionId, data); } /// <summary>
/// 用户断开
/// </summary>
/// <param name="exception"></param>
/// <returns></returns>
public override Task OnDisconnectedAsync(Exception exception)
{
if (gameLogic != null)
gameLogic.LevelUser(Context.ConnectionId);
return base.OnDisconnectedAsync(exception);
}
}
/// <summary>
/// 游戏逻辑
/// </summary>
public class GameLogic
{
/// <summary>
/// 全局客户端通信信息
/// </summary>
readonly IClientProxy gloable;
/// <summary>
/// 游戏定时器
/// </summary>
readonly Timer gameTimer;
/// <summary>
/// 所有用户
/// </summary>
public List<UserInfo> list = new List<UserInfo>(); public GameLogic(IClientProxy _gloable)
{
gloable = _gloable;
//启动模拟游戏帧
gameTimer = new Timer();
gameTimer.Elapsed += GameTimer_Elapsed;
gameTimer.Start();
} private void GameTimer_Elapsed(object sender, ElapsedEventArgs e)
{
for (int i = ; i < list.Count; i++)
{
var item = list[i];
//发送已改变状态用户信息广播
if (item.Change)
{
item.Change = false;
gloable.SendAsync("update", list[i]);
}
}
}
/// <summary>
/// 用户加入
/// </summary>
/// <param name="id">用户编号</param>
/// <param name="data">加入信息</param>
public void JoinUser(string id, Data data)
{
//随机获取角色图片
var user = new UserInfo() { Id = id, Name = data.Name, Role = "role" + new Random().Next(, ) + ".jpg", Change = true };
list.Add(user);
gloable.SendAsync("add", user);
}
/// <summary>
/// 用户断开处理
/// </summary>
/// <param name="id">用户编号</param>
public void LevelUser(string id)
{
var user = list.FirstOrDefault(mm => mm.Id == id);
if (user != null)
{
gloable.SendAsync("level", user);
list.Remove(user);
}
}
/// <summary>
/// 更新用户信息
/// </summary>
/// <param name="id">用户编号</param>
/// <param name="p">用户信息</param>
public void UpdateUserInfo(string id, UserInfo changeUser)
{
var user = list.FirstOrDefault(mm => mm.Id == id);
if (user != null)
{
user.X = changeUser.X;
user.Y = changeUser.Y;
user.Change = true;
}
}
}
/// <summary>
///用户信息
/// </summary>
public class UserInfo
{
public string Id { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 用户角色图片
/// </summary>
public string Role { get; set; }
public int X { get; set; }
public int Y { get; set; }
/// <summary>
/// 是否动作变化
/// </summary>
public bool Change { get; set; }
}
/// <summary>
/// 传输数据
/// </summary>
public class Data
{
public string Name { get; set; }
public string Value { get; set; }
}

2. 注册SignalR中间件,注册文件浏览。

    public class Startup
{ public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
} public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseDefaultFiles().UseStaticFiles();
app.UseSignalR(router => {
router.MapHub<HubHelper>("/game");
});
}
}

三、前端代码部分

1.实现 MSGGame.js 游戏消息处理js, 重写原因是:无代码提示,而且重写后方便自己扩展增加功能和相关管理。NetCore SingalR无重连功能,需要自己实现。

//消息处理
var MSG = {
isStart: false,
connection: null, /**
* 初始化信息处理 返回promis
* @param {string} _url 消息地址
* @param {Function} _func 相关绑定函数
*/
init: function (url) {
if (url == null)
url = "/game";
MSG.connection = new signalR.HubConnectionBuilder().withUrl(url).build();
},
/**
* 注册监听函数
* @param {any} key 监听键名
* @param {any} func 监听执行函数
*/
reg: function (key,func) {
MSG.connection.on(key, function (result) {
func(result);
});
},
/**启动消息 返回promis*/
start: function () {
if (MSG.isStart) {
return;
}
MSG.isStart = true;
var _result = MSG.connection.start();
_result.then(function (_return) { }).catch(function (err) {
MSG.isStart = false;
return console.error(err.toString());
});
return _result;
}, /**
* 停止消息 返回promis
* */
stop: function () {
if (!MSG.isStart) {
return;
}
var _result = MSG.connection.stop();
_result.then(function (_return) { }).catche(function (err) { });
MSG.isStart = false;
return _result;
},
/**
*
* @param {any} api
* @param {any} msg
*/
send: function (api, msg) {
if (!MSG.isStart) {
return;
}
var _result = MSG.connection.invoke(api, msg);
//回调处理
_result.then(function (_return) { });
//错误处理
_result.catch(function (_error) { });
return _result;
},
/**重新连接 未实现
*@param {number} num 尝试连接次数
*/
reconnection: function (num) {
if (MSG.isStart) { }
}
};

2.在wwwroot下建立index.html 然后编写简单逻辑

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
body {
position: relative;
} .role {
position: absolute;
} .role, img {
width: 150px;
height: 150px;
} .role > p {
position: absolute;
bottom: ;
left: ;
background: rgba(, , , 0.73);
color: red;
overflow: hidden;
text-align: center;
width: %;
} #content {
width: 200px;
height: 200px;
overflow-y: scroll
}
</style>
</head> <body>
<div>
<div id="clone_role" class="role" style="display: none;">
<p>克隆对象</p>
<img src="role1.jpg" />
</div>
<input type="text" name="name" id="userName" placeholder="你的名称!" />
<button id="sendButton">开始测试</button>
<div id="content">
输入名称,点击开始进行测试。随后随便点击屏幕。
</div>
</div>
<script src="jquery-1.10.2.min.js"></script>
<script src="signalr.min.js"></script>
<script src="game.js"></script>
<script>
$(function () {
var content = document.getElementById("content");//内容信息
var $body = $(document.body);//body容器
var userArray = new Array();//所有用户
var userPostion = { id: "", name: "", x: , y: , start: false }; //本人信息
var GameMain = {
//加载所有监听事件
load: function () {
//状态更新
MSG.reg("update", function (result) {
var user = userArray[result.id];
if (user) {
user.img.style.left = result.x + "px";
user.img.style.top = result.y + "px";
}
});
//获取编号
MSG.reg("GetId", function (result) {
userPostion.id = result;
});
//获取当前连接所有用户
MSG.reg("GetALLUser", function (result) {
if (result) {
for (var i = ; i < result.length; i++) {
GameMain.joinUser(result[i]);
}
}
});
//用户加入
MSG.reg("add", function (result) {
content.innerText += result.name + " :用户加入";
GameMain.joinUser(result);
});
//用户离开
MSG.reg("level", function (result) {
content.innerText += result.name + ":离开";
GameMain.levelUser(result);
});
},
//用户加入展示
joinUser: function (user) {
userArray[user.id] = user;
//克隆模板
var clone = $("#clone_role").clone();
clone.children("img").attr("src", user.role);
clone.children("p").text(user.name);
userArray[user.id].img = clone[];
$body.append(userArray[user.id].img);
clone.slideDown();
},
//用户离开
levelUser: function (p) {
var user = userArray[p.id];
if (user) {
document.body.removeChild(user.img);
userArray[p.id] = undefined;
}
},
//系统事件
sysEvent: function () {
//点击发送坐标
$(document).click(function (e) {
userPostion.x = e.clientX;
userPostion.y = e.clientY;
if (userPostion.start) {
MSG.send("UpdateSate", userPostion);
}
})
//点击发送加入房间信息
$("#sendButton").click(function () {
if (MSG.isStart && !userPostion.start) {
var userName = $("#userName").val();
MSG.send("Join", { name: userName, value: "" });
userPostion.start = true;
}
})
}
}; //初始化函数
MSG.init("game");
//加载消息监听及系统事件
GameMain.load();
GameMain.sysEvent();
//启动消息
MSG.start().then(function () {
MSG.send("GetId", { name: "", value: "" });
MSG.send("GetALLUser", { name: "", value: "" });
});
})
</script>
</body>
</html>

3. 最终目录结构为:

四、运行测试,打开多个网页。输入相关名称。然后点击屏幕。看看是否能联动。 可以发给自己好朋友测测看看。

五、Signalr问题说明、相关建议经验

1.Signalr 发布到 winserver 2008R2 时 无法使用websocket通信,需要进行特殊处理。

2.对于实时性要求非常高时,没有进行高并发处理过。希望处理过的人,通知我下。

3.我这有白鹭引擎、Layaair 连接Signalr 的TS代码, 也有unity 连接 net core Signalr 代码(因 unity  我用时只提供了 老版本连接方法,现在没去看是否有新可用的), 需要的可以联系我。

4. Net Core 开源后,群众呼声很高。无论是机器学习、微服务方面 微软都在逐步大力支持中, 希望大家共同努力让.Net 这么好用的东西 走得更远。

5.曾经不写博客什么的感觉没用,不过眼看.net 人员越来越少。    感叹!

6.如果想实现分布式的可参考官网,自己动手丰衣足食。

以上仅供娱乐测试。代码地址:https://github.com/840900649/SignalRTest

Net Core SignalR 测试,可以用于unity、Layair、白鹭引擎、大数据分析平台等高可用消息实时通信器。的更多相关文章

  1. Dubbo入门到精通学习笔记(十五):Redis集群的安装(Redis3+CentOS)、Redis集群的高可用测试(含Jedis客户端的使用)、Redis集群的扩展测试

    文章目录 Redis集群的安装(Redis3+CentOS) 参考文档 Redis 集群介绍.特性.规范等(可看提供的参考文档+视频解说) Redis 集群的安装(Redis3.0.3 + CentO ...

  2. [asp.net core]SignalR一个例子

    摘要 在一个后台管理的页面想实时监控一些操作的数据,想到用signalR. 一个例子 asp.net core+signalR 使用Nuget安装包:Microsoft.AspNetCore.Sign ...

  3. ASP.NET Core SignalR:基础概述

    一.简介 ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程. 实时 Web 功能使服务器端代码能够即时将内容推送到客户端. SignalR 的适用 ...

  4. Asp.Net Core SignalR 系列博客

    系列 SignalR+Vue SignalR+Vue 服务端向客户端发送信息 SignalR+Vue+Log4net 实时日志推送 待定...... 源码地址:https://github.com/Q ...

  5. .net core signalR 服务端强制中断用户连接

    .net core signalR 服务端断开连接 { } { } *:first-child { } *:last-child { } { } { } { } { } { } { } { } { } ...

  6. ASP.NET Core SignalR中的流式传输

    什么是流式传输? 流式传输是这一种以稳定持续流的形式传输数据的技术. 流式传输的使用场景 有些场景中,服务器返回的数据量较大,等待时间较长,客户端不得不等待服务器返回所有数据后,再进行相应的操作.这时 ...

  7. Asp.Net Core SignalR 用泛型Hub优雅的调用前端方法及传参

    继续学习 最近一直在使用Asp.Net Core SignalR(下面成SignalR Core)为小程序提供websocket支持,前端时间也发了一个学习笔记,在使用过程中稍微看了下它的源码,不得不 ...

  8. Asp.Net Core SignalR 与微信小程序交互笔记

    什么是Asp.Net Core SignalR Asp.Net Core SignalR 是微软开发的一套基于Asp.Net Core的与Web进行实时交互的类库,它使我们的应用能够实时的把数据推送给 ...

  9. ASP.NET Core SignalR

    ASP.NET Core SignalR 是微软开发的一套基于ASP.NET Core的与Web进行实时交互的类库,它使我们的应用能够实时的把数据推送给Web客户端. 功能 自动管理连接 允许同时广播 ...

随机推荐

  1. ImageView小技巧

    ImageView截取图片的方式 centerCrop:以中心点为基准 将图片的最短边与ImageView宽度匹配 其他部分裁掉centerInside: 以中心点为基准 将图片最长边 缩进控件去

  2. NPOI创建doc

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  3. 如何在ecplise中配置maven以及ecplise访问本地仓库

    1.m2e的插件 因为使用ecplise版本比较高,所以它自带了maven的插件,但是我们希望可以使用我们自己指定的maven.配置步骤如下: ecplise--->preperences下,点 ...

  4. Codeforces 611C. New Year and Domino 动态规划

    C. New Year and Domino time limit per test 3 seconds memory limit per test 256 megabytes input stand ...

  5. bat 调用exe

    @set errorlevel=>nul :reInput @echo 请输入批次号: @set/p 批次号= >nul @set 批次号|findstr "\\<%sea ...

  6. div 自适应宽度

    div 自适应宽度 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...

  7. Linux下JDK应该安装在哪个位置

    在百度知道上看到的回答觉得不错:https://zhidao.baidu.com/question/1692690545668784588.html 如果你认为jdk是系统提供给你可选的程序,放在op ...

  8. 2018.09.28 hdu5434 Peace small elephant(状压dp+矩阵快速幂)

    传送门 看到n的范围的时候吓了一跳,然后发现可以矩阵快速幂优化. 我们用类似于状压dp的方法构造(1(1(1<<m)∗(1m)*(1m)∗(1<<m)m)m)大小的矩阵. 然后 ...

  9. 2018.09.23 关键网线(tarjan)

    描述 给出一个无向连通图,即在任一个点对间存在路径.有的点提供服务a, 有的点提供服务b .同一个点可能有两种服务类型.每个点必须与提供2种服务的点连通.如果一个边断掉,就可能出现有些点不能被服务到, ...

  10. 2018.09.14 洛谷P3567 [POI2014]KUR-Couriers(主席树)

    传送门 简单主席树啊. 但听说有随机算法可以秒掉%%%(本蒟蒻并不会) 直接维护值域内所有数的出现次数之和. 当这个值不大于区间总长度的一半时显然不存在合法的数. 这样在主席树上二分查值就行了. 代码 ...