一、關於SignalR 1、簡介:Signal 是微軟支持的一個運行在 Dot NET 平臺上的 html websocket 框架。它出現的主要目的是實現伺服器主動推送(Push)消息到客戶端頁面,這樣客戶端就不必重新發送請求或使用輪詢技術來獲取消息。 可訪問其官方網站:https://githu ...
一、關於SignalR
1、簡介:Signal 是微軟支持的一個運行在 Dot NET 平臺上的 html websocket 框架。它出現的主要目的是實現伺服器主動推送(Push)消息到客戶端頁面,這樣客戶端就不必重新發送請求或使用輪詢技術來獲取消息。
可訪問其官方網站:https://github.com/SignalR/ 獲取更多資訊。
2、SignalR 的實現機制與 .NET WCF 或 Remoting 是相似的,都是使用遠程代理來實現。在具體使用上,有兩種不同目的的介面:PersistentConnection 和 Hubs,其中 PersistentConnection 是實現了長時間的 Javascript 輪詢(類似於 Comet),Hub 是用來解決實時信息交換問題,它是利用 Javascript 動態載入執行方法實現的。SignalR 將整個連接,信息交換過程封裝得非常漂亮,客戶端與伺服器端全部使用 JSON 來交換數據。
下麵就 Hubs 介面的使用來講講整個流程:
(1),在伺服器端定義對應的 hub class;
(2),在客戶端定義 hub class 所對應的 proxy 類;
(3),在客戶端與伺服器端建立連接(connection);
(4),然後客戶端就可以調用 proxy 對象的方法來調用伺服器端的方法,也就是發送 request 給伺服器端;
(5),伺服器端接收到 request 之後,可以針對某個/組客戶端或所有客戶端(廣播)發送消息。
以上這些都是關註大神們瞭解的。
二、具體使用
1、建立一個mvc項目 SignalR通訊
2、安裝SignalR
(1)、在SignalR通訊 項目下安裝 SignalR(找到程式包管理器控制台,輸入:Install-Package Microsoft.AspNet.SignalR)
安裝成功後系統會自動生成一個Scripts文件夾,裡面存放對應的js文件,如圖
3、安裝好環境以後。那麼接下來我們就開始搭建我們的環境及編寫相應的代碼
(1)、新建一個SignalR集線器ServerHub,如圖
並編寫以下代碼
1 public class ServerHub : Hub 2 { 3 private static readonly char[] str = 4 { 5 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 6 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 7 'w', 'x', 'y', 'z', 8 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 9 'W', 'X', 'Y', 'Z' 10 }; 11 12 /// <summary> 13 /// 消息發送介面 14 /// </summary> 15 /// <param name="message"></param> 16 public void SendMsg(string message) 17 { 18 var name = GenerateUserName(4); 19 20 // 調用所有客戶端的sendMessage方法 21 Clients.All.sendMessage(name, message); 22 } 23 24 /// <summary> 25 /// 產生隨機用戶 26 /// </summary> 27 /// <param name="length">用戶名長度</param> 28 /// <returns></returns> 29 public static string GenerateUserName(int length) 30 { 31 var newRandom = new StringBuilder(62); 32 var rd = new Random(); 33 for (var i = 0; i < length; i++) 34 { 35 newRandom.Append(str[rd.Next(62)]); 36 } 37 return newRandom.ToString(); 38 }
(2)、創建一個Startup類,(如果創建項目是有這個類。就不用添加了)添加代碼如下
public void Configuration(IAppBuilder app) { // 配置集線器 app.MapSignalR(); }
(3)、添加Home控制器及視圖Index(此步驟不截圖)
(4)、添加Index視圖代碼 如下
1 @{ 2 Layout = "~/Views/Shared/_Layout.cshtml"; 3 ViewBag.Title = "聊天視窗"; 4 } 5 6 <h2>Index</h2> 7 8 <div class="container"> 9 <input type="text" id="message" /> 10 <input type="button" id="sendmessage" value="Send" /> 11 <input type="hidden" id="displayname" /> 12 <ul id="discussion"></ul> 13 </div> 14 15 @section scripts 16 { 17 <script src="~/Scripts/jquery-1.6.4.min.js"></script> 18 <!--引用SignalR庫. --> 19 <script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script> 20 <!--引用自動生成的SignalR 集線器(Hub)腳本.在運行的時候在瀏覽器的Source下可看到 --> 21 <script src="~/signalr/hubs"></script> 22 23 <script> 24 $(function () { 25 // 引用集線器代理 26 var chat = $.connection.serverHub; 27 // 定義伺服器端調用的客戶端sendMessage來顯示新消息 28 29 chat.client.sendMessage = function (name, message) { 30 // 向頁面添加消息 31 $('#discussion').append('<li><strong>' + htmlEncode(name) 32 + '</strong>: ' + htmlEncode(message) + '</li>'); 33 }; 34 35 // 設置焦點到輸入框 36 $('#message').focus(); 37 // 開始連接伺服器 38 $.connection.hub.start().done(function () { 39 $('#sendmessage').click(function () { 40 // 調用伺服器端集線器的SendMsg方法 41 chat.server.sendMsg($('#message').val()); 42 // 清空輸入框信息並獲取焦點 43 $('#message').val('').focus(); 44 }); 45 }); 46 }); 47 48 // 為顯示的消息進行Html編碼 49 function htmlEncode(value) { 50 var encodedValue = $('<div />').text(value).html(); 51 return encodedValue; 52 } 53 </script> 54 }
4、完成以上步驟之後,我們的SignalR算是簡單的完成。讓我們來看下製作結果吧
(1)、如果出現如下錯誤,請刪除紅框里的代碼
成功之後的結果,如圖
你以為完了嘛?還沒有,別急往下看
三、頁面有優化及私聊、群聊、線上所有人接收消息的實現
1、發送所有線上人員
(1)、在layer官網下載layer前端js和ui(在我上一篇的文章中有下載地址,或者直接百度搜索layer),放到你的項目中,在這裡我們就不直接說頁面代碼的編寫部分,直接看下我們的效果圖,如下
(2)、在完成聊天之前。我們還需要做什麼,對做登錄,在這裡自動生成的用戶已經不能滿足我們接下來的需求了(登錄教程跳過)直接看登錄成功過後的界面
這樣看起來就美觀多了,其實線上所有人聊天的功能,就是剛剛我們實現那個功能是一樣的,沒有任何的變化(只是美觀了下),看看聊天結果吧
2、群聊
(1)、首先我們的建一個群聊的實體(UserGroup)和房間實體(ChatRoom),如下圖
(2)、在我們建好的ServerHub類里編寫如下代碼(具體實現看源碼)
1 public static ChatContext DbContext = new ChatContext(); 2 3 // 重寫Hub連接斷開的事件 (斷線時調用) 4 public override Task OnDisconnected(bool stopCalled) 5 { 6 // 查詢用戶 7 var user = DbContext.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId); 8 9 if (user != null) 10 { 11 // 刪除用戶 12 DbContext.Users.Remove(user); 13 14 // 從房間中移除用戶 15 foreach (var item in user.Rooms) 16 { 17 RemoveUserFromRoom(item.RoomName); 18 } 19 } 20 return base.OnDisconnected(stopCalled); 21 } 22 23 // 為所有用戶更新房間列表 24 public void UpdateRoomList() 25 { 26 var itme = DbContext.Rooms.Select(p => new { p.RoomName }); 27 var jsondata = JsonHelper.ToJsonString(itme.ToList()); 28 Clients.All.getRoomlist(jsondata); 29 } 30 31 /// <summary> 32 /// 加入聊天室 33 /// </summary> 34 public void JoinRoom(string roomName) 35 { 36 // 查詢聊天室 37 var room = DbContext.Rooms.Find(p => p.RoomName == roomName); 38 39 // 存在則加入 40 if (room == null) return; 41 42 // 查找房間中是否存在此用戶 43 var isExistUser = room.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId); 44 45 // 不存在則加入 46 if (isExistUser == null) 47 { 48 var user = DbContext.Users.Find(u => u.UserId == Context.ConnectionId); 49 user.Rooms.Add(room); 50 room.Users.Add(user); 51 52 // 將客戶端的連接ID加入到組裡面 53 Groups.Add(Context.ConnectionId, roomName); 54 55 //調用此連接用戶的本地JS(顯示房間) 56 Clients.Client(Context.ConnectionId).joinRoom(roomName); 57 } 58 else 59 { 60 Clients.Client(Context.ConnectionId).showMessage("請勿重覆加入房間!"); 61 } 62 } 63 64 /// <summary> 65 /// 創建聊天室 66 /// </summary> 67 /// <param name="roomName"></param> 68 public void CreateRoom(string roomName) 69 { 70 var room = DbContext.Rooms.Find(a => a.RoomName == roomName); 71 if (room == null) 72 { 73 var cr = new ChatRoom 74 { 75 RoomName = roomName 76 }; 77 78 //將房間加入列表 79 DbContext.Rooms.Add(cr); 80 81 // 本人加入聊天室 82 JoinRoom(roomName); 83 UpdateRoomList(); 84 } 85 else 86 { 87 Clients.Client(Context.ConnectionId).showMessage("房間名重覆!"); 88 } 89 } 90 91 public void RemoveUserFromRoom(string roomName) 92 { 93 //查找房間是否存在 94 var room = DbContext.Rooms.Find(a => a.RoomName == roomName); 95 96 //存在則進入刪除 97 if (room == null) 98 { 99 Clients.Client(Context.ConnectionId).showMessage("房間名不存在!"); 100 return; 101 } 102 103 // 查找要刪除的用戶 104 var user = room.Users.FirstOrDefault(a => a.UserId == Context.ConnectionId); 105 // 移除此用戶 106 room.Users.Remove(user); 107 //如果房間人數為0,則刪除房間 108 if (room.Users.Count <= 0) 109 { 110 DbContext.Rooms.Remove(room); 111 } 112 113 Groups.Remove(Context.ConnectionId, roomName); 114 115 //提示客戶端 116 Clients.Client(Context.ConnectionId).removeRoom("退出成功!"); 117 } 118 119 /// <summary> 120 /// 給房間內所有的用戶發送消息 121 /// </summary> 122 /// <param name="room">房間名</param> 123 /// <param name="message">信息</param> 124 public void SendMessage(string room, string message) 125 { 126 // 調用房間內所有客戶端的sendMessage方法 127 // 因為在加入房間的時候,已經將客戶端的ConnectionId添加到Groups對象中了,所有可以根據房間名找到房間內的所有連接Id 128 // 其實我們也可以自己實現Group方法,我們只需要用List記錄所有加入房間的ConnectionId 129 // 然後調用Clients.Clients(connectionIdList),參數為我們記錄的連接Id數組。 130 Clients.Group(room, new string[0]).sendMessage(room, message + " " + DateTime.Now); 131 }
(3)、在Home控制器里創建GroupUser視圖並添加如下代碼
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-1.10.2.min.js"></script> 12 <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script> 13 <script src="~/Scripts/layer/layer.js"></script> 14 <!--這裡要註意,這是虛擬目錄,也就是你在OWIN Startup中註冊的地址--> 15 <script src="/signalr/hubs"></script> 16 17 <script type="text/javascript"> 18 var chat; 19 var roomcount = 0; 20 21 $(function() { 22 chat = $.connection.serverHub; 23 chat.client.showMessage = function(message) { 24 alert(message); 25 }; 26 chat.client.sendMessage = function(roomname, message) { 27 $("#" + roomname).find("ul").each(function() { 28 $(this).append('<li>' + message + '</li>'); 29 }); 30 }; 31 chat.client.removeRoom = function(data) { 32 alert(data); 33 }; 34 chat.client.joinRoom = function (roomname) { 35 var html = '<div style="float:left; margin-left:360px; border:double; height:528px;width:493px" id="' + roomname + '" roomname="' + roomname + '"><button onclick="RemoveRoom(this)">退出</button>\ 36 ' + roomname + '房間\ 37 聊天記錄如下:<ul>\ 38 </ul>\ 39 <textarea class="ChatCore_write" id="ChatCore_write" style="width:400px"></textarea> <button onclick="SendMessage(this)">發送</button>\ 40 </div>'; 41 $("#RoomList").append(html); 42 }; 43 44 //註冊查詢房間列表的方法 45 chat.client.getRoomlist = function(data) { 46 if (data) { 47 var jsondata = $.parseJSON(data); 48 $("#roomlist").html(" "); 49 for (var i = 0; i < jsondata.length; i++) { 50 var html = ' <li>房間名:' + jsondata[i].RoomName + '<button roomname="' + jsondata[i].RoomName + '" onclick="AddRoom(this)">加入</button></li>'; 51 $("#roomlist").append(html); 52 } 53 } 54 }; 55 // 獲取用戶名稱。 56 $('#username').html(prompt('請輸入您的名稱:', '')); 57 58 $.connection.hub.start().done(function() { 59 $('#CreatRoom').click(function() { 60 chat.server.createRoom($("#Roomname").val()); 61 }); 62 }); 63 }); 64 65 function SendMessage(btn) { 66 var message = $(btn).prev().val(); 67 var room = $(btn).parent(); 68 var username = $("#username").html(); 69 message = username + ":" + message; 70 var roomname = $(room).attr("roomname"); 71 chat.server.sendMessage(roomname, message); 72 $(btn).prev().val('').focus(); 73 } 74 75 function RemoveRoom(btn) { 76 var room = $(btn).parent(); 77 var roomname = $(room).attr("roomname"); 78 chat.server.removeUserFromRoom(roomname); 79 } 80 81 function AddRoom(roomname) { 82 var data =$(roomname).attr("roomname"); 83 chat.server.joinRoom(data); 84 } 85 86 </script> 87 </head> 88 <body> 89 <div> 90 <div>名稱:<p id="username"></p></div> 91 輸入房間名: 92 <input type="text" value="聊天室1" id="Roomname" /> 93 <button id="CreatRoom">創建聊天室</button> 94 </div> 95 <div style="float:left;border:double"> 96 <div>房間列表</div> 97 <ul id="roomlist"></ul> 98 </div> 99 <div id="RoomList"> 100 </div> 101 </body> 102 </html>
(4)、做好以上步驟之後,主要的功能已經實現,那麼接下來我們看下效果 如下
點擊發送群聊之後出現如圖所示
並創建自己的用戶名
我們在創建自己的用戶名之後,可以選擇自己創建房間或者加入已有的房間,如下圖
3、私聊
(1)、私聊我們在這裡就不多說了。實現原理和群里差不多。都是找到對應的人員id就ok,直接上圖看結果
源碼請加qq群:460362190 裡面有更多的開源項目哦,歡迎加入討論
如果你還滿意請點擊關註和推薦,謝謝