1. 程式人生 > 實用技巧 >SignalR訊息推送(03)

SignalR訊息推送(03)

目錄:

  • SignalR概念
  • 基本使用
  • 對點聊天

1.SignalR

是微軟為實現實時通訊而開發的一個類庫。可進行分散式實時通訊,遠端代理實現。

1.1兩大內部物件

  • Persisten Connection

   用於客戶端和伺服器端的持久連線。

  • Hub(集線器)物件

  用於資訊互動,將伺服器端的資料推送(push)至客戶端。

原理:客端建立與服端的連線。客端呼叫服端的方法。服端通過客端傳送的請求,響應資料,呼叫客端的方法將資料推送至客端。

1.2 基本使用

  • 建立一個MVC應用程式。
  • 在MVC專案的Models資料夾中新增新項 SignalR Hub集線器類。
在建立的Hub類中新增如下程式碼:

//hub別名,方便前臺呼叫 [HubName("getMsg")] public class MyHub : Hub { public void Send(string title,string msg) { //呼叫客戶端的sendMessage()方法 Clients.All.sendMessage(title,msg); //其中Clients.All是dynamic型別,sendMessaage()方法是檢視中js定義的function。 } }
  • 在專案中新增 OWIN StartUp 類。
public class Startup
{
public void Configuration(IAppBuilder app)
{
//註冊管道,使用預設的虛擬地址,根目錄下的"/signalr", //當然你也可以自己定義 app.MapSignalR(); } }
  • 建立控制器和檢視
//建立MessageController,並建立兩個用於顯示檢視的action。
//控制器程式碼:
ublic class MessageController : Controller
{
//傳送訊息
public ActionResult SendMessage()
{
return View();
}
//接收訊息
public ActionResult ReceiveMessage()
{
return View();
}
}

//傳送訊息檢視程式碼:
<h2>傳送訊息</h2> <div> 標題:<input type="text" id="title" /> </div><br /> <div> 內容:<textarea id="message" rows="4" cols="30"></textarea> </div> <br /> <div> <input type="button" id="sendmessage" value="傳送" /> </div> <script src="~/Scripts/jquery.signalR-2.2.2.js"></script> <!--引用自動生成的SignalR 集線器(Hub)指令碼.在執行的時候在瀏覽器的Source下可看到 --> <script src="~/signalr/hubs"></script> <script type="text/javascript"> $(function () { // 引用自動生成的集線器代理(此處使用別名getMsg) var chat = $.connection.getMsg; // 整合器連線開始 $.connection.hub.start().done(function () { // 服務連線完成,給傳送按鈕註冊單擊事件 $('#sendmessage').click(function () { // 呼叫伺服器端集線器的Send方法 chat.server.send($("#title").val(), $('#message').val()); //又呼叫了客戶端,客戶端的函式就是新增資訊列,就實現了廣播訊息功能 }); }); }); </script> //接收訊息檢視程式碼: <h2>接收訊息</h2> <div> <br /> <div id="msgcontent"></div> </div> <script src="~/Scripts/jquery.signalR-2.2.2.js"></script> <script src="~/signalr/hubs"></script> <script type="text/javascript"> $(function () { // 引用自動生成的集線器代理 var chat = $.connection.getMsg; // 定義伺服器端呼叫的客戶端sendMessage來顯示新訊息 chat.client.sendMessage = function (title, message) { // 向頁面傳送接收的訊息 var html = "<div>標題:" + title + "訊息內容:" + message + "</div>"; $("#msgcontent").after(html); }; // 整合器連線開始 $.connection.hub.start(); //與SignalR服務建立連線 }); </script>

//<!--引用SignalR庫. -->

<!--引用SignalR庫. -->

<script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>

<!--引用自動生成的SignalR 集線器(Hub)指令碼 -->

<script src="~/signalr/hubs"></script>

1.3 實現點對點聊天

Clients物件的所有屬性或方法,具體的定義如下:

public interface IHubConnectionContext<T>
{
T All { get; } // 代表所有客戶端
T AllExcept(params string[] excludeConnectionIds); //除了引數中的所有客戶端
T Client(string connectionId); // 特定的客戶端,實現端對端聊天的關鍵
T Clients(IList<string> connectionIds); // 引數中的客戶端
T Group(string groupName, params string[] excludeConnectionIds); // 指定客戶端組,可以實現群聊
T Groups(IList<string> groupNames, params string[] excludeConnectionIds);
T User(string userId); // 特定的使用者
T Users(IList<string> userIds); // 引數中的使用者
}
屬性

SignalR會每一個客戶端分配一個ConnnectionId

實現思路:

  • 客戶端登入的時候記錄下客戶端的ConnnectionId,並將使用者加入到一個靜態陣列中,該資料為了記錄所有線上使用者。
  • 使用者可以點選線上使用者中的使用者聊天,在傳送訊息的時候,需要將ConnectionId一併傳入到服務端。
  • 服務端根據傳入的訊息內容和ConnectionId呼叫Clients.Client(connnection).sendMessage方法來進行轉發到對應的客戶端。
[HubName("Chat")]
public class ChatHub : Hub
{
// 靜態屬性,線上使用者列表
public static List<UserInfo> OnlineUsers = new List<UserInfo>();

//登入
public void Login(string userId,string userName)
{
//獲取客戶端的ConnectionId
var connnectId = Context.ConnectionId;
OnlineUsers.Add(new UserInfo
{
ConnectionId = connnectId,
UserId = userId,
UserName = userName
});
// 所有客戶端同步線上使用者
Clients.All.loadUser(OnlineUsers);
}

/// <summary>
/// 傳送私聊
/// </summary>
/// <param name="toUserId">接收方使用者連線ID</param>
/// <param name="message">內容</param>
public void SendPrivateMessage(string toUserId, string message)
{
var fromUserId = Context.ConnectionId;
var toUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == toUserId);
var fromUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == fromUserId);
if (toUser != null && fromUser != null)
{
// 呼叫指定使用者的客戶端方法
Clients.Client(toUserId).receivePrivateMessage(fromUser.UserName, message);
}
else
{
//表示對方不線上
Clients.Caller.absentSubscriber();
}
}
   
/// <summary>
/// 斷線時呼叫
/// </summary>
/// <param name="stopCalled"></param>
/// <returns></returns>
public override Task OnDisconnected(bool stopCalled)
{
var user = OnlineUsers.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId);

// 判斷使用者是否存在,存在則刪除
if (user == null) return base.OnDisconnected(stopCalled);
Clients.All.onUserDisconnected(user.ConnectionId, user.UserName); //呼叫客戶端使用者離線通知
// 刪除使用者
OnlineUsers.Remove(user);
return base.OnDisconnected(stopCalled);
}
}


//客戶端程式碼:
<h2>聊天系統</h2>
<div class="container">
@using (Html.BeginForm("login", "Chat", FormMethod.Post, new { @class = "form-inline" }))
{
<label>使用者Id:</label>
@Html.TextBox("userId", "", new { @class = "form-control" })
<label>使用者名稱:</label>
@Html.TextBox("userName", "", new { @class = "form-control" })
<input type="button" id="btnLogin" value="登入" class="btn btn-default" />
}
</div>
<hr />
<div class="container">
<div class="col-md-3">
<div class="panel panel-default">
<div class="panel-heading">
線上使用者
</div>
<div class="panel-body">
<ul id="userList">
</ul>
</div>
</div>
</div>
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
聊天內容
</div>
<div class="panel-body">
<ul id="msgList" >
</ul>
</div>
<div class="panel-footer">
<label>訊息To:</label> <label id="toUser"></label>
@Html.TextBox("msg", "", new { @class = "form-control form-inline" })
<input type="button" id="btnSend" value="傳送" class="btn btn-default" />
</div>
</div>
</div>
</div>
@section scripts{
<script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>
//使用者點選(選擇使用者)
function selectUser(li) {
var connectionId = $(li).attr("cid");
$('#toUser').text(connectionId);
}
$(function () {
var chat = $.connection.Chat;

//重新整理線上列表
chat.client.loadUser = function (allUsers) {
$('#userList').html("");
for (var i = 0; i < allUsers.length; i++) {
var li = $('<li cid="' + allUsers[i].ConnectionId+'" onclick="selectUser(this)">' + allUsers[i].UserId + ':' + allUsers[i].UserName + '</li> ');
$('#userList').append(li);
}
}
//接收訊息
chat.client.receivePrivateMessage = function (from, msg) {
var li = $("<li>來自:" + from + "<br/>" + msg + "</li>");
$("#msgList").append(li);
}
 
$.connection.hub.start().done(function () {
console.log("連線完成");
//登入
$('#btnLogin').click(function () {
chat.server.login($("#userId").val(), $('#userName').val())
})


$('#btnSend').click(function () {
chat.server.sendPrivateMessage($('#toUser').text(), $('#msg').val())
})
});
})
</script>
實現