Web實時通訊,SignalR真香,不用愁了

Code綜藝圈發表於2021-11-08

前言

對於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就是一個類,只是裡面編寫的方法客戶端可以遠端呼叫到(原理後續我們們一起讀讀原始碼);同樣在服務端也可以遠端用客戶端的方法,這樣就使得實時通訊變得簡單便捷了。

    image-20211106142039335

  • 在Startup.cs檔案中註冊相關服務及管道

    image-20211106142220483

  • 業務API編寫,推送訊息

    其實上面的步驟已經完成SignalR服務端搭建,接下來需要加入一些業務模擬,比如模擬訊息推送,方便演示;如下編寫API:

    image-20211106143018397

    到這服務端的業務就寫完了,接下來就是開始編寫客戶端。

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地址形式引入,並沒有下載到本地,真實專案中肯定是要自己管理的。如下:

    image-20211106143756693

    關鍵指令碼邏輯,如下:

    image-20211106144326661

    注:這裡需要注意客戶端指定的方法名和接到的引數的解析,是駝峰的形式。

  • 執行起來演示釋出效果,如下:

    image-20211106145304681

    是不是很簡單就實現了推送效果,根本就沒咋敲程式碼,是不是很香。 到這小夥伴會問,其他客戶端型別支援嗎?答案是肯定的,什麼後臺服務或窗體都行,接下來就搞個窗體的客戶端。對了,Java客戶端也支援,只管放心用,不僅僅是.Net。

    注:有小夥伴自己開發執行的時候訪問不到頁面,那因為WebApi專案中預設不支援靜態頁面訪問,需要加上對應的中介軟體,如下:

    image-20211106145517082

2.3 WinForm客戶端

佈局很簡單,在窗體中直接搞個文字框顯示訊息就行; 小夥伴們別嫌棄啊,主要體現的是流程,介面美化小夥伴們自己想怎麼搞都行。

image-20211106150325984

核心程式碼如下:

image-20211106150802587

客戶端又很輕鬆的搞定了,執行起來看看效果:

先把伺服器執行起來(這裡是WebApi專案),然後窗體程式執行起來:

image-20211106151551325

實現起來是不是很給力,現在不用再苦惱對於B/S模式下,伺服器端主動的場景了吧;

2.4 客戶端主動上報資料資訊,實時顯示到其他客戶端

上面的推送場景是服務端主動, 但有很多場景是客戶端主動上報資料,需要實時顯示到資料看板或顯示到其他客戶端介面。比如一些監控系統,需要實時顯示裝置狀態;再比如類似遊戲的場景,其中一個客戶端發生改變,需要實時顯示到其他客戶端。

對應客戶端主動上報的場景,需要通過伺服器轉發,因為客戶端之間沒有建立連線,只有伺服器知道有多少客戶端已連上,所以這個時候需要在服務端上增加一個方法供客戶端呼叫,如下步驟:

  • 服務端在自定義的MyHub中增加一個方法

    image-20211106155011998

  • 這裡模擬的是在窗體客戶端發生資料改變,實時顯示到其他客戶端

    image-20211106155721773

    在窗體客戶端按鈕的點選事件中直接呼叫服務端的方法,並傳遞更新的資訊,由服務端呼叫客戶端的方法再轉發給其他客戶端

  • 客戶端的更新方法,這裡只在Js客戶端實現,其他客戶端如果需要,同理

    image-20211106160249302

  • 執行起來看效果

    image-20211106160637325

2.5 小結

上面列舉了兩個場景,伺服器主動推和客戶端主動推兩種情況,基本上可以滿足大多數實時需求。通訊流程圖如下:

  • 服務端推送訊息

    image-20211106190406197

    1.Js客戶端點選發布按鈕呼叫API介面;

    2.介面內部將資訊交給SignalR處理;

    3.獲取所有客戶端,並通過遠端呼叫客戶端方法的方式將資訊傳遞給客戶端,最後資訊就可以實時展示了。

  • 客戶端上報資料

    image-20211106190708596

    1.在窗體客戶端中點選按鈕,內部呼叫服務端的UpdateDataServer方法;

    2.服務端被呼叫之後,內部獲取所有客戶端,並呼叫客戶端中updatedata方法;最後在客戶端將資訊展示。

案例原始碼地址:https://gitee.com/CodeZoe/dot-net-core-study-demo/tree/main/SignalRDemo

總結

關於SignalR的簡單使用先說這麼多,便捷又好用;還有一些關鍵的知識點後續會分享,比如針對分組和使用者發資訊、新增認證管理等,關注“Code綜藝圈”,和我一起學習吧;

相關文章