一. 聲明 該節主要介紹SignalR的一些理論知識,代碼量很小,在後續章節編寫中,會不斷回來更新該節,完善該節的介紹;待該系列結束時,該節會和目錄章節合併。 下麵的理論介紹相對枯燥,但對於後面的理解有一定意義,不感興趣的朋友可以右上角離開了,從下一節開始,正式開始擼代碼。 原計劃三天更新一篇,結果 ...
一. 聲明
該節主要介紹SignalR的一些理論知識,代碼量很小,在後續章節編寫中,會不斷回來更新該節,完善該節的介紹;待該系列結束時,該節會和目錄章節合併。 下麵的理論介紹相對枯燥,但對於後面的理解有一定意義,不感興趣的朋友可以右上角離開了,從下一節開始,正式開始擼代碼。原計劃三天更新一篇,結果周五下班前忘記提交代碼了,加上周六公司組織活動,該系列推遲一天,今天大清早跑到公司,務必也要寫完這一節,這裡分享一下昨天公司組織活動拍攝的照片。
上面廢話說多了,下麵進入正題。
二. SignalR簡介
SignalR是微軟的一個開源項目,為客戶端和伺服器端實時通訊的問題提供了很好的解決方案,通過簡單的配置和API調用,即可完成相應的通訊功能的開發。
(PS:截止目前【2018-07-08】最新版本為 2.3.0,GitHub地址為:https://github.com/SignalR/SignalR)
前面一節提到已經有了WebSocket,那麼為什麼還要SignalR呢?
首先WebSocket相容性存在問題,針對這一點,SignalR對目前為止幾類主流的傳輸協議進行了封裝,讓瀏覽器自行選擇可以相容的版本(當然也可以自行指定),這樣就解決了開發者使用WebSocket時候的痛點了。
SignalR大一統:
它封裝了 WebSocket、ForeverFrame、ServerSentEvents、LongPolling四種主要的傳輸協議。
① WebSocket:它是HTML5提供的一種在單個 TCP 連接上進行全雙工通訊的協議。
② ForeverFrame(永久幀):它適用於IE瀏覽器,是在頁面中插入一個隱藏的iframe,利用其src屬性在伺服器和客戶端之間創建一條長鏈接,伺服器向iframe傳輸數據(通常是HTML,內有負責插入信息的javascript),來實時更新頁面。
③ SeverSentEvents(伺服器發送事件,也成EventSourse):顧名思義。
④ longPolling(Ajax長輪詢):長輪詢是對輪詢的改進,客戶端通過請求連接到伺服器,並保持一段時間的連接狀態,直到消息更新或超時才返回Response並中止連接,可以有效減少無效請求的次數。
如何指定傳輸協議:
(1). 預設選擇:conn.start().done(function () {});
(2). 手動指定:conn.start({ transport: 'serverSentEvents' }).done(function () {});
註. 可選參數有:webSockets、foreverFrame、serverSentEvents、longPolling
(3). 手動指定多個,如果不相容,依次向後選擇:conn.start({ transport: ['foreverFrame','webSockets'] }).done(function () {});
這裡簡單分享一下我這裡使用的代碼,不介紹了後面章節有詳細的介紹。
前端代碼:
1 @{ 2 Layout = null; 3 } 4 5 <!DOCTYPE html> 6 7 <html> 8 <head> 9 <meta name="viewport" content="width=device-width" /> 10 <title>Index</title> 11 <script src="~/Scripts/jquery-3.3.1.min.js"></script> 12 <script src="~/Scripts/jquery.signalR-2.3.0.js"></script> 13 <script type="text/javascript"> 14 $(function () { 15 var conn = $.connection("/myPreConnection1"); 16 //開啟日誌 17 conn.logging = true; 18 19 //1. 預設的形式選擇 20 conn.start().done(function () { 21 22 }); 23 24 //2. 手動指定通訊方式 25 //webSockets、foreverFrame、serverSentEvents、longPolling 26 //conn.start({ transport: 'serverSentEvents' }).done(function () { 27 28 //}); 29 30 //3. 手動指定多個通訊方式,按順序選擇(第一個不支持的話,依次往後類推) 31 //conn.start({ transport: ['foreverFrame','webSockets'] }).done(function () { 32 33 //}); 34 35 }); 36 </script> 37 </head> 38 <body> 39 <div> 40 </div> 41 </body> 42 </html>View Code
OWIN Startup Class:
1 using System; 2 using System.Threading.Tasks; 3 using Microsoft.Owin; 4 using Owin; 5 6 [assembly: OwinStartup(typeof(SignalRDemo.Startup))] 7 8 namespace SignalRDemo 9 { 10 public class Startup 11 { 12 public void Configuration(IAppBuilder app) 13 { 14 // 有關如何配置應用程式的詳細信息,請訪問 https://go.microsoft.com/fwlink/?LinkID=316888 15 16 app.MapSignalR<MyPresitentConnection1>("/myPreConnection1"); 17 } 18 } 19 }View Code
永久連接模型類
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading.Tasks; 5 using System.Web; 6 using Microsoft.AspNet.SignalR; 7 8 namespace SignalRDemo 9 { 10 public class MyPresitentConnection1 : PersistentConnection 11 { 12 //下麵的兩個方法OnConnected 和 OnReceived預設帶的 13 14 /// <summary> 15 /// 連接成功後的方法(已測試) 16 /// </summary> 17 /// <param name="request"></param> 18 /// <param name="connectionId"></param> 19 /// <returns></returns> 20 protected override Task OnConnected(IRequest request, string connectionId) 21 { 22 return Connection.Send(connectionId, "Welcome!"); 23 } 24 25 /// <summary> 26 /// 接收請求的方法(已測試) 27 /// </summary> 28 /// <param name="request"></param> 29 /// <param name="connectionId"></param> 30 /// <param name="data"></param> 31 /// <returns></returns> 32 protected override Task OnReceived(IRequest request, string connectionId, string data) 33 { 34 return Connection.Broadcast(data); 35 } 36 37 } 38 }View Code
測試一下:
① 預設的形式
② 手動指定
可以自行去測試不同瀏覽器不同版本相容哪些協議,這裡就不在過多測試了。
如果不指定協議,預設選擇傳輸的協議的順序為:
三. 兩種通訊模型
SignalR客戶端和伺服器端通訊有兩種模型:分別是永久連接模型(PresistentConnection)和中心模型(Hubs),其中永久連接更加偏向底層,代碼編寫與原生的WebSocket很像,我個人不是很喜歡這種模式;中心模型Hubs更像面向開發者的模式,它實質上是對PresitentConnection做了封裝,使其更加友好,個人非常推薦這種模式,該模式有一個非常好的地方,它允許客戶端和伺服器端自定義方法然後相互之間調用。
(1). PresistentConnection:用於單個發件人、分組、廣播消息的簡單終結點,開發人員通過使用持久性連接Api,直接訪問SignalR公開的底層通信協議。
(2). Hub: 基於永久連接之上更高層的封裝,它允許客戶端和伺服器端自定義方法並且相互調用,它還允許將強類型的參數傳遞給方法並且綁定模型。
下麵可以很好的說明這兩種模式的關係
簡單看看PresitentConnection模型的代碼和WebSocket確實有點像。
1 <script type="text/javascript"> 2 $(function () { 3 var conn = $.connection("/myPreConnection1"); 4 //1. 開啟連接 5 conn.start().done(function () { 6 7 }); 8 //2. 接受伺服器發來的消息 9 conn.received(function (data) { 10 console.log(data); 11 }); 12 //3. 連接斷開的方法 13 conn.disconnected(function () { 14 $("#j_notice").html("連接中斷"); 15 }); 16 17 18 //斷開連接事件 19 $("#j_close").click(function () { 20 conn.stop(); 21 }); 22 23 //群發事件 24 $("#j_send").click(function () { 25 conn.send("你好啊"); 26 }); 27 28 }); 29 </script>View Code
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading.Tasks; 5 using System.Web; 6 using Microsoft.AspNet.SignalR; 7 8 namespace SignalRDemo 9 { 10 public class MyPresitentConnection1 : PersistentConnection 11 { 12 //下麵的兩個方法OnConnected 和 OnReceived預設帶的 13 14 /// <summary> 15 /// 連接成功後的方法(已測試) 16 /// </summary> 17 /// <param name="request"></param> 18 /// <param name="connectionId"></param> 19 /// <returns></returns> 20 protected override Task OnConnected(IRequest request, string connectionId) 21 { 22 return Connection.Send(connectionId, "Welcome!"); 23 } 24 25 /// <summary> 26 /// 接收請求的方法(已測試) 27 /// </summary> 28 /// <param name="request"></param> 29 /// <param name="connectionId"></param> 30 /// <param name="data"></param> 31 /// <returns></returns> 32 protected override Task OnReceived(IRequest request, string connectionId, string data) 33 { 34 return Connection.Broadcast(data); 35 } 36 37 /// <summary> 38 /// 連接中斷調用方法(已測試) 39 /// </summary> 40 /// <param name="request"></param> 41 /// <param name="connectionId"></param> 42 /// <param name="stopCalled"></param> 43 /// <returns></returns> 44 protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled) 45 { 46 return base.OnDisconnected(request, connectionId, stopCalled); 47 } 48 49 /// <summary> 50 /// 當連接在超時後重新連接時調用該方法 51 /// </summary> 52 /// <param name="request"></param> 53 /// <param name="connectionId"></param> 54 /// <returns></returns> 55 protected override Task OnReconnected(IRequest request, string connectionId) 56 { 57 return base.OnReconnected(request, connectionId); 58 } 59 } 60 }View Code
四. 一些環境的要求
1. .Net Framework的版本
SignalR 2 起僅支持在 .Net FrameWork 4.5及以上。
2. 操作系統
Win7、Win8、Win10、WinServer 2008 R2、WinServer 2012、WinServer 2016.
註:如果SignalR使用WebSocket協議,需要配置啟動Web套接字。
3. IIS版本
首先IIS必須使用集成模式,不支持經典模式,另外如果SignalR使用WebSocket協議的話,必須使用IIS8及以上。
註:程式必須在完全信任的模式下運行。
4. web瀏覽器對傳輸協議的要求
首先配合使用的JQuery版本需在 1.6.4 及以上。
5. 桌面程式對傳輸協議的要求
該節到此結束,寫了大約兩個小時,下一個章節開始擼代碼,先介紹PresistentConnection這種模式,大約下周二(2018-7-10)更新,感興趣的朋友可以關註一下,相互學習。
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,如需代碼請在評論處留下你的郵箱