SignalR介绍来源于微软文档,不过多解释。https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction?view=aspnetcore-2.1html
ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程。 实时 Web 功能使服务器端代码可以即时将内容推送到客户端。前端
SignalR 的适用对象:jquery
如下是 ASP.NET Core SignalR 的一些功能:git
以上是SignalR介绍,除了以上说明外还有以下优势:github
1. 建立Hub中间件 HubHelper,及游戏简单处理逻辑类web
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(30); gameTimer.Elapsed += GameTimer_Elapsed; gameTimer.Start(); } private void GameTimer_Elapsed(object sender, ElapsedEventArgs e) { for (int i = 0; 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(1, 4) + ".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中间件,注册文件浏览。redis
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无重连功能,须要本身实现。json
//消息处理 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 而后编写简单逻辑api
<!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: 0; left: 0; background: rgba(102, 102, 102, 0.73); color: red; overflow: hidden; text-align: center; width: 100%; } #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: 0, y: 1, 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 = 0; 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[0]; $body.append(userArray[user.id].img); clone.slideDown(400); }, //用户离开 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: "0" }); userPostion.start = true; } }) } }; //初始化函数 MSG.init("game"); //加载消息监听及系统事件 GameMain.load(); GameMain.sysEvent(); //启动消息 MSG.start().then(function () { MSG.send("GetId", { name: "0", value: "0" }); MSG.send("GetALLUser", { name: "0", value: "0" }); }); }) </script> </body> </html>
3. 最终目录结构为:服务器
1.Signalr 发布到 winserver 2008R2 时 没法使用websocket通讯,须要进行特殊处理。
2.对于实时性要求很是高时,没有进行高并发处理过。但愿处理过的人,通知我下。
3.我这有白鹭引擎、Layaair 链接Signalr 的TS代码, 也有unity 链接 net core Signalr 代码(因 unity 我用时只提供了 老版本链接方法,如今没去看是否有新可用的), 须要的能够联系我。
4. Net Core 开源后,群众呼声很高。不管是机器学习、微服务方面 微软都在逐步大力支持中, 但愿你们共同努力让.Net 这么好用的东西 走得更远。
5.曾经不写博客什么的感受没用,不过眼看.net 人员愈来愈少。 感叹!
6.若是想实现分布式的可参考官网,本身动手丰衣足食。