ASP.NET Core實時庫SignalR簡介及使用
何為實時
先從理論上解釋一下兩者的區別。
大多數傳統的web應用是這樣的:客戶端發起http請求到服務端,服務端返回對應的結果。像這樣:
也就是說,傳統的web應用都是客戶端主動發起請求到服務端。
那麼實時web應用呢?它不需要主動發起請求,服務端可以主動推送信息到客戶端。
舉栗子的話,實時聊天工具、web遊戲等都可以算是實時應用。
什麼是SignalR
如果想做一個實時應用,最好用web socket。很早以前我也寫過web socket的實現方式,但不夠全面,這裡再補上一篇。
來說說signalR,它是一款開源的實時框架,可以使用三種方式實現通信(long polling、server sent events、web socket)。它很好的整合瞭底層技術,讓我們可以不用關註底層技術實現而把精力聚焦在業務實現上。一個完整的signalR包括客戶端和服務端,服務端支持net core/net framework,還支持大部分客戶端,比如瀏覽器和桌面應用。
回落機制
為瞭兼容不同瀏覽器(客戶端)和服務端,signalR采用瞭回落機制,使得它可以根據情況協商使用不同的底層傳輸方式。假如瀏覽器不支持web socket,就自動降級使用sse,再不行就long polling。當然,也可以禁用這種機制,指定其中一種。
三種通信方式
long polling(長輪詢)
長輪詢是客戶端發起請求到服務端,服務器有數據就會直接返回。如果沒有數據就保持連接並且等待,一直到有新的數據返回。如果請求保持到一段時間仍然沒有返回,這時候就會超時,然後客戶端再次發起請求。
這種方式優點就是簡單,缺點就是資源消耗太多,基本是不考慮的。
server sent events(sse)
如果使用瞭sse,服務器就擁有瞭向客戶端推送的能力,這些信息和流信息差不多,期間會保持連接。
這種方式優點還是簡單,也支持自動重連,綜合來講比long polling好用。缺點也很明顯,不支持舊的瀏覽器不說,還隻能發送本文信息,而且瀏覽器對sse還有連接數量的限制(6個)。
web socket
web socket允許客戶端和服務端同時向對方發送消息(也就是雙工通信),而且不限制信息類型。雖然瀏覽器同樣有連接數量限制(可能是50個),但比sse強得多。理論上最優先使用。
進入正題
開始之前,還需要瞭解RPC和Hub的概念。
- RPC:全稱Remote Procedure Call,字面意思遠程服務調用,可以像調用本地方法一樣調用遠程服務。前端可以調用後端方法,後端也可以調用前端方法。
- Hub:基於RPC,接受從客戶端發過來的消息,也同時負責把服務端的消息發送給客戶端。客戶端可以調用Hub裡面的方法,服務端可以通過Hub調用客戶端裡面的方法。
好瞭,概念已經理解清楚瞭,接下來上代碼。
在項目裡新增Hub類:
using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace SignalRDemo.Server { public class SignalRHub : Hub { /// <summary> /// 客戶連接成功時觸發 /// </summary> /// <returns></returns> public override async Task OnConnectedAsync() { var cid = Context.ConnectionId; //根據id獲取指定客戶端 var client = Clients.Client(cid); //向指定用戶發送消息 await client.SendAsync("Self", cid); //像所有用戶發送消息 await Clients.All.SendAsync("AddMsg", $"{cid}加入瞭聊天室"); } } }
為瞭讓外部可以訪問,我們還需要一個控制器。在控制器裡聲明隨便建一個:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; using SignalRDemo.Server; using System.Threading.Tasks; namespace SignalRDemo.Controllers { public class HomeController : Controller { private readonly IHubContext<SignalRHub> _countHub; public HomeController(IHubContext<SignalRHub> countHub) { _countHub = countHub; } /// <summary> /// 發送信息 /// </summary> /// <param name="msg"></param> /// <param name="id"></param> /// <returns></returns> public async Task Send(string msg, string id) { await _countHub.Clients.All.SendAsync("AddMsg", $"{id}:{msg}"); } } }
再然後進入StartUp設置端點:
endpoints.MapHub<SignalRHub>("/hub");
完成以後,配置signalr客戶端:
setupConn = () => { conn = new signalR.HubConnectionBuilder() .withUrl("/hub") .build(); conn.on("AddMsg", (obj) => { $('#msgPanel').append(`<p>${obj}</p>`); }); conn.on("Finished", () => { conn.stop(); $('#msgPanel').text('log out!'); }); conn.on("Self", (obj) => { $('#userId').text(obj); }); conn.start() .catch(err => console.log(err)); }
要註意withUrl裡面的路徑就是之前設置好的端點。
運行效果:
Hub還支持組操作,比如:
//將用戶添加到A組 await Groups.AddToGroupAsync(Context.ConnectionId, "GroupA"); //將用戶踢出A組 await Groups.RemoveFromGroupAsync(Context.ConnectionId, "GroupA"); //向A組所有成員廣播消息 await Clients.Group("GroupA").SendAsync("AddMsg", "群組消息");
更多操作請參考官方文檔。
本文演示demo的源碼見git,地址:https://gitee.com/muchengqingxin/SignalRDemo.git
到此這篇關於ASP.NET Core實時庫SignalR簡介及使用的文章就介紹到這瞭。希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 基於ABP框架實現數據字典開發
- ASP.NET Core的中間件與管道介紹
- .Net Core使用SignalR實現鬥地主遊戲
- 淺析.net core 拋異常對性能影響
- GO使用socket和channel實現簡單控制臺聊天室