最近一段時間因目前在職公司的一些狀況及我的的職業規劃,參加面試幾家金融股票應用軟件及信息管理的企業,對於問的比較統一的或是比較多的就是如何利用服務器的消息推送實現股票證券行情的實時更新,根據我的的項目總結及網上其餘博主的資源總結了利用SignalR技術實現實施更新。html
Asp.net SignalR是微軟爲實現實時通訊的一個類庫。通常狀況下,SignalR會使用JavaScript的長輪詢(long polling)的方式來實現客戶端和服務器通訊,隨着Html5中WebSockets出現,SignalR也支持WebSockets通訊。另外SignalR開發的程序不單單限制於宿主在IIS中,也能夠宿主在任何應用程序,包括控制檯,客戶端程序和Windows服務等,另外還支持Mono,這意味着它能夠實現跨平臺部署在Linux環境下。jquery
SignalR內部有兩類對象:面試
SignalR將整個信息的交換封裝起來,客戶端和服務器都是使用JSON來溝通的,在服務端聲明的全部Hub信息,都會生成JavaScript輸出到客戶端,.NET則依賴Proxy來生成代理對象,而Proxy的內部則是將JSON轉換成對象。瀏覽器
客戶端和服務端的具體交互狀況以下圖所示:服務器
從上面的介紹能夠看出,SignalR既然是爲實時而生的,這樣就決定了其使用場所。具體適用情景有以下幾點:併發
經過第二部分的介紹,相信你們對Asp.net SignalR有了一個初步的瞭解,接下來經過兩個例子來讓你們加深對SignalR運行機制的理解。第一個例子就是在Web端如何使用SignalR來實現廣播消息。app
4. 向項目中添加一個SignalR集線器(v2)並命名爲ServerHub。dom
5. 將下面代碼填充到剛剛建立的ServerHub類中。ide
using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; using System; namespace SignalRQuickStart {public class ServerHub : Hub { private static readonly char[] Constant = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; /// <summary> /// 供客戶端調用的服務器端代碼 /// </summary> /// <param name="message"></param> public void Send(string message) { var name = GenerateRandomName(4); // 調用全部客戶端的sendMessage方法 Clients.All.sendMessage(name, message); } /// <summary> /// 產生隨機用戶名函數 /// </summary> /// <param name="length">用戶名長度</param> /// <returns></returns> public static string GenerateRandomName(int length) { var newRandom = new System.Text.StringBuilder(62); var rd = new Random(); for (var i = 0; i < length; i++) { newRandom.Append(Constant[rd.Next(62)]); } return newRandom.ToString(); } } }
6. 建立一個Startup類,若是開始建立MVC項目的時候沒有更改身份驗證的話,這個類會默認添加的,若是已有就不須要重複添加了。按照以下代碼更新Startup類。函數
7. 在Home控制器中建立一個Home Action方法
public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } public ActionResult Chat() { return View(); } }
8. 在Views文件中Home文件夾中建立一個Chat視圖,視圖代碼以下所示:
@{ ViewBag.Title = "聊天窗口"; } <h2>Chat</h2> <div class="container"> <input type="text" id="message" /> <input type="button" id="sendmessage" value="Send" /> <input type="hidden" id="displayname" /> <ul id="discussion"></ul> </div> @section scripts { <!--引用SignalR庫. --> <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script> <!--引用自動生成的SignalR 集線器(Hub)腳本.在運行的時候在瀏覽器的Source下可看到 --> <script src="~/signalr/hubs"></script> <script> $(function () { // 引用自動生成的集線器代理 var chat = $.connection.serverHub; // 定義服務器端調用的客戶端sendMessage來顯示新消息 chat.client.sendMessage = function (name, message) { // 向頁面添加消息 $('#discussion').append('<li><strong>' + htmlEncode(name) + '</strong>: ' + htmlEncode(message) + '</li>'); }; // 設置焦點到輸入框 $('#message').focus(); // 開始鏈接服務器 $.connection.hub.start().done(function () { $('#sendmessage').click(function () { // 調用服務器端集線器的Send方法 chat.server.send($('#message').val()); // 清空輸入框信息並獲取焦點 $('#message').val('').focus(); }); }); }); // 爲顯示的消息進行Html編碼 function htmlEncode(value) { var encodedValue = $('<div />').text(value).html(); return encodedValue; } </script> }
9. 修改App_Start文件夾內的RoutConfig類,將Action方法默認設置爲Chat.
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Chat", id = UrlParameter.Optional } ); } }
到此,咱們的例子就實現完成了,接下來咱們先來看看運行效果,以後再來解釋到底SignalR是如何來完成廣播消息的。運行的運行結果以下。
從運行結果,你能夠發現,在任何一個窗口輸入信息併發送,全部客戶端將收到該消息。這樣的效果在實際應用中不少,如QQ,一登陸QQ的時候都會推送騰訊廣告消息。
看完了運行結果,接下來咱們來分析下代碼,進而來剖析下SignalR究竟是如何工做的。
按照B/S模式來看,運行程序的時候,Web頁面就與SignalR的服務創建了鏈接,具體的創建鏈接的代碼就是:$.connection.hub.start()。這句代碼的做用就是與SignalR服務創建鏈接,後面的done函數代表創建鏈接成功後爲發送按鈕註冊了一個click事件,當客戶端輸入內容點擊發送按鈕後,該Click事件將會觸發,觸發執行的操做爲: chat.server.send($('#message').val())。這句代碼表示調用服務端的send函數,而服務端的Send韓式又是調用全部客戶端的sendMessage函數,而客戶端中sendMessage函數就是將信息添加到對應的消息列表中。這樣就實現了廣播消息的功能了。
看到這裏,有人是否會有疑問,前面的實現都只用到了集線器對象,而沒有用到持久鏈接對象。其實並非如此,$.connection這句代碼就是使用持久鏈接對象,固然你也能夠在從新OnConnected方法來查看監控客戶端的鏈接狀況,更新的代碼以下所示:
public class ServerHub : Hub { private static readonly char[] Constant = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; /// <summary> /// 供客戶端調用的服務器端代碼 /// </summary> /// <param name="message"></param> public void Send(string message) { var name = GenerateRandomName(4); // 調用全部客戶端的sendMessage方法 Clients.All.sendMessage(name, message); } /// <summary> /// 客戶端鏈接的時候調用 /// </summary> /// <returns></returns> public override Task OnConnected() { Trace.WriteLine("客戶端鏈接成功"); return base.OnConnected(); } /// <summary> /// 產生隨機用戶名函數 /// </summary> /// <param name="length">用戶名長度</param> /// <returns></returns> public static string GenerateRandomName(int length) { var newRandom = new System.Text.StringBuilder(62); var rd = new Random(); for (var i = 0; i < length; i++) { newRandom.Append(Constant[rd.Next(62)]); } return newRandom.ToString(); } }
這樣在運行頁面的時候,將在輸出窗口看到「客戶端鏈接成功」字樣。運行效果以下圖所示:
在第二部分介紹的時候說道,在服務端聲明的全部Hub信息,都會生成JavaScript輸出到客戶端,爲了驗證這一點,能夠在Chrome中F12來查看源碼就明白了,具體以下圖所示:
看到上圖,你也就明白了爲何Chat.cshtml頁面須要引入"signalr/hubs"腳本庫了吧。
<!--引用SignalR庫. --> <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script> <!--引用自動生成的SignalR 集線器(Hub)腳本.在運行的時候在瀏覽器的Source下可看到 --> <script src="~/signalr/hubs"></script>
參考文獻:http://www.cnblogs.com/zhili/p/SignalRQuickStart.html