在上一章講到了廣播推送,即所有訂閱的用戶都能收到,這種適合於信息廣播。
接下來介紹如何給指定的對象推送
在講這個之前先說明一下連接創建的基礎知識
1、每個頁面與服務端創建連接並啟動時,這時服務端會產生一個connectionId作為與這個客戶端連接的唯一標識。
2、這個connectionId將作為服務端向指定客戶端推送的依據
3、同一個頁面刷新后ConnectionId一樣不變
4、這個connectionId是服務端自動生成的一個隨機數,無法變更。
一、只推送給自己
為了與之前的例子區分,我們分別在服務端DemoHub新建個發送給自己的方法
public class DemoHub : Hub { /// <summary> /// 示例 /// </summary> /// <param name="content">廣播的內容</param> public void Hello(string content) { Clients.All.show(content); //調用了前端js上定義的hello方法 } /// <summary> /// 推送給自己 /// </summary> /// <param name="content"></param> public void CallSelf(string content) { Clients.Caller.show(content); } }
這里使用了Caller,而不是All,表示只推送給呼叫方,即自己。
前端腳本邏輯不變,只是多了一個發送給自己的按鈕的推送到服務端CallSelf事件而已。
//定義推送 $.connection.hub.start() .done(function () { $("#btn_sendCall").click(function () { chat.server.callSelf($("#content").val()); //將客戶端的content內容發送到服務端 $("#content").val(""); }); });
結果:
我是在窗口2這邊發送的,第一條點擊“發送”按鈕,是廣播,兩個窗口都能收到;第二條點擊“發送給自己”,只有窗口2收到。
二、其他推送方式
其他推送方式對於客戶端(前端)來說不變,主要就是服務端推送對象改變而已
以下列出其他推送方式:
- 所有連接的客戶端
Clients.All.show(content); - 僅調用的客戶端
Clients.Caller.show(content); - 除調用客戶端之外的所有客戶端
Clients.Others.show(content); - 特定的客戶端標識的連接 id
Clients.Client(Context.ConnectionId).show(content); - 所有連接的客戶端除外指定客戶端,由連接 ID 標識
Clients.AllExcept(connectionId1, connectionId2).show(content); - 指定組中的所有連接的客戶端
Clients.Group(groupName).show(content); - 指定組中的所有連接的客戶端除外指定客戶端,由連接 ID 標識。
Clients.Group(groupName, connectionId1, connectionId2).show(content); - 所有連接的客戶端指定組中除調用客戶端
Clients.OthersInGroup(groupName).show(content); - 所有客戶端和組列表中的連接 Id
Clients.Clients(ConnectionIds).show(content); - 組的列表。
Clients.Groups(GroupIds).show(content); - 按名稱的用戶
Clients.Client(username).show(content); //這里的username我還沒理解是怎么創建的 - (在 SignalR 2.1 中引入) 的用戶名稱的列表。
Clients.Users(new string[] { "myUser", "myUser2" }).show(content)
三、說說ConnectionId
前面已經說到,每個連接的頁面都會產生不同的連接id,並且這個連接id是隨機產生,不能自定義的,那我們如何獲取呢
集線器中為我們提供了Context對象可以獲取到這個連接id,先看下面簡單的例子
/// <summary> /// 返回每個連接的id /// </summary> public void ReturnConnectionId() { Clients.Caller.show(Context.ConnectionId); }
前端:
//定義推送,返回各個客戶端連接 $.connection.hub.start() .done(function () { $("#btn_sendConnectionId").click(function () { chat.server.returnConnectionId(); //將客戶端的content內容發送到服務端 }); });
結果:
從結果可以看出,分別點擊返回各自的id,返回了不同的id。這個就驗證了系統給每個調用端分配一個不相同的隨機ConnectionId。
那我們如何利用這個ConnnectionId來實現給某個客戶端發送消息,比如一對一的聊天。這個就需要我們實現將人與ConnectionId信息建立對應關系。
如,我們假設張三和李四一對一聊天,那怎么實現,張三發送李四的消息只有李四收到呢,反之,亦然。即我們需要分別確定張三和李四的ConnectionId,並將它們的ConnnectionId與張三、李四建立對應關系。
即建立以下的對應關系
張三 張三的ConnectionId
李四 李四的ConnectionId
張三和李四是已知的,那么就需要在張三和李四分別與集線器建立連接生成ConnenctionId時,我們就要實現對應關系的建立。
這時候需要重載建立連接的方法:
服務端:
/// <summary> /// 發送給指定連接 /// </summary> /// <param name="toName"></param> /// <param name="content"></param> public void CallOne(string toName,string content) { //根據username獲取對應的ConnectionId var connectionId = HttpContext.Current.Application[toName].ToString(); Clients.Client(connectionId).show(content); } /// <summary> /// 初次連接 /// </summary> /// <returns></returns> public override Task OnConnected() { string username = Context.QueryString["userName"]; //獲取客戶端發送過來的用戶名 string connectionId = Context.ConnectionId; HttpContext.Current.Application.Add(username,connectionId); //存儲關系 return base.OnConnected(); }
客戶端:建立zhangsan.html和lisi.html 分別表示張三和李四的窗口
zhangsan.html
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <link href="Content/bootstrap.min.css" rel="stylesheet" /> <script src="Scripts/jquery-1.10.2.min.js"></script> <script src="Scripts/jquery.signalR-2.3.0.min.js"></script> <script src="/signalr/hub/hubs"></script> <meta charset="utf-8"/> <style type="text/css"> body { margin: 20px; } .input { padding-left: 5px; } </style> </head> <body> <div> <h4>我是張三</h4> <p> <input type="text" id="content" placeholder="" class="input"/> <input type="button" value="發送給李四" class="btn btn-sm btn-info" id="btn_send"/> </p> <div> <h4>接收到的信息:</h4> <ul id="dataContainer"> </ul> </div> </div> <script language="javascript"> $(function() { var chat = $.connection.demoHub; //連接服務端集線器,demoHub為服務端集線器名稱,js上首字母須改為小寫(系統默認) //定義客戶端方法,此客戶端方法必須與服務端集線器中的方法名稱、參數均一致。 //實際上是服務端調用了前端的js方法(訂閱) $.connection.hub.qs = { 'userName': '張三' } chat.client.show=function(content) { var html = '<li>' + htmlEncode(content) + "</li>"; $("#dataContainer").append(html); } //定義推送 $.connection.hub.start() .done(function() { $("#btn_send").click(function() { chat.server.callOne("李四",$("#content").val()); //將客戶端的content內容發送到服務端 $("#content").val(""); }); }); }); //編碼 function htmlEncode(value) { var encodedValue = $('<div />').text(value).html(); return encodedValue; } </script> </body> </html>
lisi.html:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <link href="Content/bootstrap.min.css" rel="stylesheet" /> <script src="Scripts/jquery-1.10.2.min.js"></script> <script src="Scripts/jquery.signalR-2.3.0.min.js"></script> <script src="/signalr/hub/hubs"></script> <meta charset="utf-8" /> <style type="text/css"> body { margin: 20px; } .input { padding-left: 5px; } </style> </head> <body> <div> <h4>我是李四</h4> <p> <input type="text" id="content" placeholder="" class="input" /> <input type="button" value="發送給張三" class="btn btn-sm btn-info" id="btn_send" /> </p> <div> <h4>接收到的信息:</h4> <ul id="dataContainer"></ul> </div> </div> <script language="javascript"> $(function() { var chat = $.connection.demoHub; //連接服務端集線器,demoHub為服務端集線器名稱,js上首字母須改為小寫(系統默認) //定義客戶端方法,此客戶端方法必須與服務端集線器中的方法名稱、參數均一致。 //實際上是服務端調用了前端的js方法(訂閱) $.connection.hub.qs = { 'userName': '李四' } chat.client.show=function(content) { var html = '<li>' + htmlEncode(content) + "</li>"; $("#dataContainer").append(html); } //定義推送 $.connection.hub.start() .done(function() { $("#btn_send").click(function() { chat.server.callOne("張三", $("#content").val()); //將客戶端的content內容發送到服務端 $("#content").val(""); }); }); }); //編碼 function htmlEncode(value) { var encodedValue = $('<div />').text(value).html(); return encodedValue; } </script> </body> </html>
說明:
1、參數傳遞的方法
$.connection.hub.qs = { 'userName': '李四' }
2、后端獲取參數的方法:
Context.QueryString["username"]
3、本例中利用Application對象來存儲用戶與ConnectionId的對應關系,當然,實際項目中也可以用其他方式存儲。
示例結果:
本章結束!