前言
對於B/S模式的項目,基礎的場景都是客戶端發起請求,服務端返回響應結果就結束了一次連接;但在很多實際應用場景中,這種簡單的請求和響應模式就顯得很吃力,比如消息通知、監控看板信息自動刷新等實時通信場景,小伙伴們肯定會想到輪詢或WebSocket的方式來搞定,可是單純用輪詢的方式有點耗資源,只用WebSocket的方式又有些瀏覽器或其他客戶端不支持,所以如果自己從頭來寫的話,很多細節還得做處理;這個時候SignalR就該站出來了,封裝的很給力,直接使用就行。
正文
1. SignalR簡介
SignalR是一個開源的庫,跨平台;讓Web應用與其他應用通訊變得很簡單,Web服務端可以實時的將內容推送給對應的客戶端,客戶端發送的信息也可以實時到其他客戶端。
SignalR提供了一種遠程過程調用(RPC)的方式,使得客戶端可以調用服務器的方法,同樣在服務器端的方法中也能調用客戶端的方法。
1.1 SignalR的通信方式
SignalR支持如下的方式實現實時通信:
- WebSockets:是一種在單個TCP連接上進行全雙工通信的協議,使得服務器和瀏覽器的通信更加簡單,服務端可以主動發送信息。
- Server-Sent Events:SSE 與 WebSocket 作用相似,都是建立瀏覽器與服務器之間的通信渠道,然后服務器向瀏覽器推送信息。WebSocket是雙向的,而SSE是單向的。
- Long Polling(長輪詢) :和傳統的輪詢原理一樣,只是服務端不會每次都返回響應信息,只有有數據或超時了才會返回,從而減少了請求次數。
SignalR會自動選擇服務器和客戶端能力范圍內的最佳通信方式(是不是很優秀) ,當然也可以手動指定。
1.2 SignalR的應用場景
其實對於Web模式下的實時通信,SignalR用上試試,感覺還是很給力的。
- 服務端主動推送信息;比如發送公告場景;
- 監控或看板數據實時顯示;比如監控系統實時展示分布到各個客戶端上的數據;
- 服務端和客戶端交互;比如客服系統的聊天場景。
理論大概先說這么多,接下來就用實例演示一波。
2. 案例演示
2.1 SignalR服務端
這里我把SignalR的服務端寄宿在WebAPI項目中了,實際可以根據需要寄宿到對應的項目(窗體應用、后台服務),當然也可以單獨為其創建一個項目,但代碼編寫都基本一樣。
-
創建一個WebAPI項目,引入對應的Nuget包
-
編寫自己的SignalR Hub
Hub就是一個類,只是里面編寫的方法客戶端可以遠程調用到(原理后續咱們一起讀讀源碼);同樣在服務端也可以遠程用客戶端的方法,這樣就使得實時通信變得簡單便捷了。
-
在Startup.cs文件中注冊相關服務及管道
-
業務API編寫,推送消息
其實上面的步驟已經完成SignalR服務端搭建,接下來需要加入一些業務模擬,比如模擬消息推送,方便演示;如下編寫API:
到這服務端的業務就寫完了,接下來就是開始編寫客戶端。
2.2 JS客戶端
Js客戶端使用Vue組件,綁定數據方便;放在WebApi項目的wwwroot目錄下,和WebAPI一起共用服務器啟動,所以就不用考慮跨域問題。如果前端分開部署,需要在SignalR寄宿的項目中配置跨域。具體步驟如下:
-
獲取signalr封裝好的js文件,開箱即用
npm init -y npm install @microsoft/signalr
npm將包內容安裝在當前執行命令目錄下的node_modules@microsoft\signalr\dist\browser文件夾中。在服務端項目中創建wwwroot/signalr文件夾,將下載下來signalr.js文件復制到wwwroot\signalr文件夾即可;
采用npm的方式需要提前安裝node,也可以直接下載。不過在真正前端項目中,npm安裝完直接引入就使用了,不需要來回拷貝,這里只是演示。
-
編寫index.html
這里把所有的靜態文件都放在WebAPI項目的wwwroot目錄下,到時候一塊共用服務器;另外使用到Vue和異步請求,所以需要引入Vue和axios的js文件,這里都是通過CDN地址形式引入,並沒有下載到本地,真實項目中肯定是要自己管理的。如下:
關鍵腳本邏輯,如下:
注:這里需要注意客戶端指定的方法名和接到的參數的解析,是駝峰的形式。
-
運行起來演示發布效果,如下:
是不是很簡單就實現了推送效果,根本就沒咋敲代碼,是不是很香。 到這小伙伴會問,其他客戶端類型支持嗎?答案是肯定的,什么后台服務或窗體都行,接下來就搞個窗體的客戶端。對了,Java客戶端也支持,只管放心用,不僅僅是.Net。
注:有小伙伴自己開發運行的時候訪問不到頁面,那因為WebApi項目中默認不支持靜態頁面訪問,需要加上對應的中間件,如下:
2.3 WinForm客戶端
布局很簡單,在窗體中直接搞個文本框顯示消息就行; 小伙伴們別嫌棄啊,主要體現的是流程,界面美化小伙伴們自己想怎么搞都行。
核心代碼如下:
客戶端又很輕松的搞定了,運行起來看看效果:
先把服務器運行起來(這里是WebApi項目),然后窗體程序運行起來:
實現起來是不是很給力,現在不用再苦惱對於B/S模式下,服務器端主動的場景了吧;
2.4 客戶端主動上報數據信息,實時顯示到其他客戶端
上面的推送場景是服務端主動, 但有很多場景是客戶端主動上報數據,需要實時顯示到數據看板或顯示到其他客戶端界面。比如一些監控系統,需要實時顯示設備狀態;再比如類似游戲的場景,其中一個客戶端發生改變,需要實時顯示到其他客戶端。
對應客戶端主動上報的場景,需要通過服務器轉發,因為客戶端之間沒有建立連接,只有服務器知道有多少客戶端已連上,所以這個時候需要在服務端上增加一個方法供客戶端調用,如下步驟:
-
服務端在自定義的MyHub中增加一個方法
-
這里模擬的是在窗體客戶端發生數據改變,實時顯示到其他客戶端
在窗體客戶端按鈕的點擊事件中直接調用服務端的方法,並傳遞更新的信息,由服務端調用客戶端的方法再轉發給其他客戶端。
-
客戶端的更新方法,這里只在Js客戶端實現,其他客戶端如果需要,同理
-
運行起來看效果
2.5 小結
上面列舉了兩個場景,服務器主動推和客戶端主動推兩種情況,基本上可以滿足大多數實時需求。通信流程圖如下:
-
服務端推送消息
1.Js客戶端點擊發布按鈕調用API接口;
2.接口內部將信息交給SignalR處理;
3.獲取所有客戶端,並通過遠程調用客戶端方法的方式將信息傳遞給客戶端,最后信息就可以實時展示了。
-
客戶端上報數據
1.在窗體客戶端中點擊按鈕,內部調用服務端的UpdateDataServer方法;
2.服務端被調用之后,內部獲取所有客戶端,並調用客戶端中updatedata方法;最后在客戶端將信息展示。
案例源碼地址:https://gitee.com/CodeZoe/dot-net-core-study-demo/tree/main/SignalRDemo
總結
關於SignalR的簡單使用先說這么多,便捷又好用;還有一些關鍵的知識點后續會分享,比如針對分組和用戶發信息、添加認證管理等,關注“Code綜藝圈”,和我一起學習吧;