Net Core SignalR 測試,能夠用於unity、Layair、白鷺引擎、大數據分析平臺等高可用消息實時通訊器。

SignalR介紹

SignalR介紹來源於微軟文檔,不過多解釋。https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction?view=aspnetcore-2.1html

ASP.NET Core SignalR 是一個開源代碼庫,它簡化了嚮應用添加實時 Web 功能的過程。 實時 Web 功能使服務器端代碼可以即時將內容推送到客戶端。前端

SignalR 的適用對象:jquery

  • 須要來自服務器的高頻率更新的應用。 例如:遊戲、社交網絡、投票、拍賣、地圖和 GPS 應用。
  • 儀表板和監視應用。 示例包括公司儀表板、銷售狀態即時更新或行程警示。
  • 協做應用。 協做應用的示例包括白板應用和團隊會議軟件。
  • 須要通知的應用。 社交網絡、電子郵件、聊天、遊戲、行程警示以及許多其餘應用都使用通知。

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

  • 自動管理鏈接。
  • 同時向全部鏈接的客戶端發送消息。 例如,聊天室。
  • 將消息發送到特定的客戶端或客戶端組。
  • 擴展以處理增長的流量。

以上是SignalR介紹,除了以上說明外還有以下優勢:github

  • 它可支持各個平臺通訊。只要可使用websocket就能夠進行鏈接。
  • 並且進行了大量優化處理,很是方便開發者使用。
  • 擁有自由可擴展性,可經過redis 方式搭建分佈式socket通訊,支持成千上萬人不是夢。
  • 自定義協議,除了json協議外、還支持MessagePack協議。還能夠本身定義相關協議進行擴展。
  • 能夠用於unity、Layair、白鷺引擎、大數據分析平臺等高頻率使用消息實時通訊器。

SignalR使用

1、  新建項目,新建一個空Asp.net core 網站

2、引用SignalR中間件

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"); }); } }

3、前端代碼部分

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. 最終目錄結構爲:服務器

 

4、運行測試,打開多個網頁。輸入相關名稱。而後點擊屏幕。看看是否能聯動。 能夠發給本身好朋友測測看看。

 

5、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

相關文章
相關標籤/搜索