您当前的位置: 首页 > 

君子居易

暂无认证

  • 0浏览

    0关注

    210博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

SignalR灵魂所在Hub模型及再探聊天室样例

君子居易 发布时间:2019-03-14 14:48:48 ,浏览量:0

 

一. 整体介绍

  本节:开始介绍SignalR另外一种通讯模型Hub(中心模型,或者叫集线器模型),它是一种RPC模式,允许客户端和服务器端各自自定义方法并且相互调用,对开发者来说相当友好。

  该节包括的内容有:

    ①:从零搭建

    ②:Hub模型和URL匹配,默认模式和指定路径

    ③:服务器端代码介绍

    ④:客户端的两种模式,代理和非代理,各自的写法

    ⑤:服务器端和客户端包含的方法和各自如何自定义方法并且相互调用

    ⑥:第三方调用的问题,比如:如何在控制器中调用客户端的方法。

    ⑦:再探聊天室样例

 

 

二. 从零搭建

 1. 新建MVC5项目,通过Nuget安装程序集:Microsoft.AspNet.SignalR,安装成功后如下图。

2. 新建一个中心模型Hub类(MySpecHub1),该类继承了Hub类,并且几个必要方法可以override。

 

3. 新建一个OWIN Startup Class(Startup),并在Configuration方法中指定使用的通讯模型的URl,  这里采用默认的方式:如: app.MapSignalR(); 【后续展开介绍如何指定URL及其中的问题】

  PS: 程序启动时候首先会找到该类,然后运行里面的Configuration方法,从而url和通讯模型的匹配将生效。

 

4. 引入必要的JS文件,进行前端代码的编写,如下图。【后续详细介绍】

 

三. 模型和URL匹配

   我们都知道,在OWIN Startup Class(即Startup类)中Configuration方法中进行模型URL的指定,并且在很多例子中,看到都是这么写:app.MapSignalR(); 貌似并没有配置URL,但事实上并不是这样的,我们通过反编译代码可以看到,它会默认指定一个路径  "/signalr"  ,如下图:

  特别注意:这里的"/signalr",与js端的自动生成代理类的代码:没有任何毛线关系,这两个根本不是一个东西!!!!!,只是路径相似而已罢了。

   那么如何指定路径:

  通过 代码:app.MapSignalR("/myhub1", new HubConfiguration()); 可以将路径指定为:"/myhub1",至于前端页面怎么与之匹配,在下面介绍。

  PS:这里还可以配置其它参数,如下图:

 

 

四. 服务器端代码介绍

   前端页面的JS代码有两种模式,代理模式和非代理模式(下面介绍),但无论JS使用哪种模式,服务器端的代码都是唯一不变。

1. MySpecHub1类继承成Hub类,所以可以Override三个方法:

  (1). OnConnected:连接成功时调用

  (2). OnDisconnected:连接断开时调用

  (3). OnReconnected:重连时调用

2. 自定义方法

  服务器端可以自定义方法供客户端调用,比如:  public void AddUser(string userName, string userId){....}

    特别特别注意:前端【代理模式】的情况下调用的服务器端方法或者与代理文件建立连接时,有一个非常坑爹的规则,首字母必须小写,比如服务器端定义方法为:“AddUserMsg”,前端【代理模式】情况下调用必须写成:“addUserMsg”;再比如这里的Hub类为 "MySpecHub1",前端调用的时候必须写成"mySpecHub1";对此我表示很无语,当年这一点坑了我很久!!!

  PS:上述指定是【代理模式】,【非代理模式】不存在这个问题。

虽然我们已经知道这个规则了,但经常写着写着就忘了,那么如何解决上面这个问题呢?:

  这里有两个特性分别是:[HubName()] 和  [HubMethodName()],可以自行指定Hub类和自定义方法的名称,指定为什么,前端调用就用什么,这样【代理模式】下,坑爹的首字母小写规则,就不存在了。为了后续不麻烦,所以我通常在每个方法上面都加: [HubMethodName(nameof(方法名))],这样就不会存在问题了,如下图:

  

 3. 上下文对象(this.Context)

  (1). 当前用户的标记: this.Context.ConnectionId (Guid生成,不会重复)

  (2). 其它信息:RequestCookies、Headers、QueryString、User、Request

4. 如何调用客户端方法 

  使用Clients对象进行调用,Clients对象下的属性和方法有:

    ① 向所有人发送(包括自己):All { get; }

    ② 向所有人发送(排除一些人):AllExcept(params string[] excludeConnectionIds);

    ③ 向指定人发送,一对一:Client(string connectionId);

    ④ 向一些人发送,一对多:Clients(IList connectionIds);

    ⑤ 向某个组发送(排除一些人):Group(string groupName, params string[] excludeConnectionIds);

    ⑥ 向多个组发送(排除一些人):Groups(IList groupNames, params string[] excludeConnectionIds);

    ⑦ 由Id标识的特定用户:Users(IList userIds);

    ⑧ 由Id标识的特定多用户:User(string userId);

  调用形式比如:Clients.All.客户端方法名称

5. 组的概念(Groups对象)

  ① 将连接添加到指定组:Task Add(string connectionId, string groupName);

  ② 从指定组中删除连接:Task Remove(string connectionId, string groupName);

  调用如:this.Groups.Add("", "");

截图几段代码:

 

五. 客户端(js)代码介绍-代理模式

 1. 必备JS文件的引入

  前端Html页面使用SignalR,必须引入两个文件:JQuery和SignalR,必须JQuery在上,且最低版本为1.6.4,不能再低了。如下图:

2. 代理JS代码的生成

   代理JS代码用于帮助客户端调用服务器端自定义方法,注意这里的引入路径只能是:  或者  ,至于为什么路径非要这么写?这个地方不纠结了,我们姑且就这么使用(有兴趣探讨一下内部原理吧)。

  引入该代码后,进入页面F12,会发现多了JS代码,没错,这就是自动生成的代理代码,在前端代码的编写中,需要依赖该文件。

  可能会用人问,我把自动生成的这个JS代码拷贝出来,单独放到一个JS文件里,然后在页面引入,并去掉生成代理代码的这句话 ,行不行呢?

  答案是:肯定行。

    但这种拷贝出来的方式有点Low,服务器端代码只要一改,我就需要重新拷贝一遍,那么有没有别的方便的方法呢?

    显然有,大约有两种方法。

  ①:借助Microsoft.AspNet.SignalR.Utils程序集和指令。

  ②:借助Microsoft.AspNet.SignalR.Utils程序集和VS开发工具

  在这一节里,暂时不介绍这两种方式,后面章节详细介绍。

3. 如何与服务器Hub模型路径相配?

  在上面的代码中介绍过,服务器Hub模型默认的URL为"/signalr",那么客户端的代码怎么写呢?

1   //1. 与服务器路径进行匹配
2   var conn = $.connection.hub;
3   //2. 与生成的代理类建立连接
4   var proxy = $.connection.mySpecHub1;

  乍一看,丝毫没有看到与"/signalr"相关的代码,不要急,这时去看一下自动生成代理类中的代码,如下图:

  

  我们再看一下SignalR的JS代码中关于hubConnection方法的声明,如下图:

 

 

   配合第二个截图简单分析一下这块源代码,首先if判断" 一真或为真",只要!url 和 useDefaultPath有一个是真的就进入方法体内部,然后在拼接 url+“/signalr”,如果不进入if方法体,那么你输入的url是什么,这里用的就是什么。

  前面的代码为: signalR.hub = $.hubConnection("/signalr", { useDefaultPath: false }); ||两边都为false,进入不了if方法体内部,所以URL就是默认输入的“/signalr”。

4. 坑爹的调用规范

  在代理模式中,客户端调用服务器端方法或者与代理建立连接的时候,比如:

  ①:服务器端的Hub名称为MySpecHub1,客户端调用的时候必须为首字母小写:$.connection.mySpecHub1;

  ②:服务器端自定义的方法为SendSingleMsg,客户端调用的时候必须为首字母小写:proxy.server.sendSingleMsg;

  注:非代理模式中则不存在这个问题!!!!

  解决: 引入两个特性[HubName("")] 和 [HubMethodName("")]  ,放在服务器端代码上面,就解决了。 (详见服务器端代码)

5. 客户端方法的声明和调用服务器端方法

  ①. 声明客户端方法: proxy.client.xxx = function (x1, x2) {}       xxx代表客户端方法名称

  ②. 调用服务器端方法: proxy.server.xxx(x1,x2);                          xxx代表服务器端方法名称

 注:这里的proxy,是 $.connection.mySpecHub1; 与自动生成的代理类建立连接。

6. 服务器端指定模型URL后,前端如何匹配?

  如服务器端代码为:app.MapSignalR("/myhub1", new HubConfiguration());

  ①. 当使用自动生成代理类js文件时候,与冲突,暂时未解决 (欢迎下方留言讨论)

  ②. 手动引入代理类时候可以使用,只需添加 conn.url = "/myhub1"; 即可以将路径改为 "/myhub1"。 

代码如下:

通过Fiddler检测一下。

 

7. 其它方法

  同PersistentConnection模式中相同,比如建立连接和检测断线。

 

 

六. 客户端(js)代码介绍-非代理模式 

   有了前面代理模式的铺垫,非代理模式就很容易了,下面介绍一下在使用上的一些区别:

1. 基本使用

  不需要引入 或者 ,也不需要引入手动添加的代理类 ,但在代码上要这么写,比如创建代理类: $.hubConnection().CreateHubProxy("MySpecHub1");

详细代码如下:

1  //1. 与服务器路径进行匹配
2 var conn = $.hubConnection();
3 //2. 手动创建代理类
4  var proxy = conn.createHubProxy("MySpecHub1");

2. 在非代理模式中,服务器端的Hub名称和服务器端自定义的方法不必首字母小写(PS:小写也能用)

  ①:服务器端的Hub名称为MySpecHub1,客户端调用的时候 conn.createHubProxy("MySpecHub1");

  ②:服务器端自定义的方法为SendSingleMsg,客户端调用的时候必须为首字母小写: proxy.invoke("SendSingleMsg", $("#j_receiveId").val(), $("#j_content").val());

  注:服务器端的两个特性[HubName("")] 和 [HubMethodName("")]仍然好用!!!

3. 声明客户端方法和调用服务器端方法

  ①. 声明客户端方法: proxy.on("方法名",function(x1,x2,x3){});

  ②. 调用服务器端方法: proxy.invoke("方法名", "参数1","参数2","参数3");

4 默认路径匹配

  在不使用代理的情况下,$.hubConnection()与服务器路径进行匹配的时候,通过Fiddler可以发现,默认是"/signalr"路径

5. 服务器端指定路径模型路径:

  如服务器端代码为:app.MapSignalR("/myhub1", new HubConfiguration());

  客户端对应的代码为:$.hubConnection("/myhub1", { useDefaultPath: false });

  注:通过Fidder或者调试源代码,可以看到路径已经改为"/myhub1";

  特别补充:如果客户端代码var conn = $.hubConnection("/myhub1")这么写,useDefaultPath这个属性默认为true,则最后的路径为:"/myhub1/signalr",原因借助前面的分析很容易理解了。

 

 

七. 第三方调用 

  上面介绍的所有代码都是直接基于 Hub模型这个类来通信的,但在很多情况下,  发送信息之前需要进行很多其他业务的处理,这个时候所有的代码都写在Hub类中就不太合适了,  这时候需要借助控制器里的Action来通信,那么问题来了,如何通过调用控制器里的方法来实现发送信息的功能呢?

  其实非常简单,我们只需要通过 GlobalHost.ConnectionManager.GetHubContext(); 获取到这个Hub即可。

  代码如下:

复制代码

 1        /// 
 2         /// 向所有人发送消息
 3         /// 
 4         /// 当前用户的登录标记
 5         /// 发送的信息
 6         public string MySendAll(string myConnectionId ,string msg)
 7         {
 8             //Hub模式
 9             var hub = GlobalHost.ConnectionManager.GetHubContext();
10             hub.Clients.AllExcept(myConnectionId).receiveMsg($"用户【{myConnectionId}】发来消息:{msg}");
11             return "ok";
12         } 

复制代码

 

八. 聊天室样例

   在本系列的第一节,基于WebSocket写了一个聊天室样例,还吐槽了一番,写法很麻烦,这里基于Signalr的Hub模型,再写一次聊天室,并补充几个新功能。

  效果图如下:

  包括的功能有:

  ①:连接成功后通知所有人包括自己登录成功。

  ②:离线后,通知除了自己以外的所有人已经离开。

  ③:通过输入接收人的ConnectionId,实现一对一发送信息。

  ④: 通过点击群发按钮,向除了自己以外的所有人发送信息。

  ⑤:可以进入room1或room2房间,然后实现向指定房间内的所有人发送信息。

  ⑥:调用控制器中中的方法进行通讯

下面分享代码,包括(Hub模型代码,控制器代码,前端代码(代理和非代理两套))

Hub模型代码

  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 using Microsoft.AspNet.SignalR.Hubs;
  8 
  9 namespace HubDemo
 10 {
 11   
 12 
 13     //[HubName("MySpecHub1")]
 14     public class MySpecHub1 : Hub
 15     {
 16 
 17         /**************************************下面是Override的方法*************************************************/
 18 
 19 
 20         #region 01-连接成功的时候调用
 21         /// 
 22         /// 连接成功的时候调用
 23         /// 
 24         /// 
 25         public override Task OnConnected()
 26         {
 27 
 28             //调用客户端的方法通知所有人包括自己
 29             Clients.All.LoginSuccessNotice($"用户【{this.Context.ConnectionId}】登录成功", this.Context.ConnectionId);
 30             //回传给客户端自己的CId
 31             Clients.Client(this.Context.ConnectionId).ReceiveOwnCid(this.Context.ConnectionId);
 32             return base.OnConnected();
 33         }
 34         #endregion
 35 
 36         #region 02-连接断开的时候调用
 37         /// 
 38         /// 连接断开的时候调用
 39         /// 
 40         /// 
 41         /// 
 42         public override Task OnDisconnected(bool stopCalled)
 43         {
 44             //除去自己以外的消息
 45             Clients.AllExcept(this.Context.ConnectionId).receiveMsg($"用户【{this.Context.ConnectionId}】已经离开");
 46             return base.OnDisconnected(stopCalled);
 47         }
 48         #endregion
 49 
 50         #region 03-重新连接的时候调用
 51         /// 
 52         /// 重新连接的时候调用
 53         /// 
 54         /// 
 55         public override Task OnReconnected()
 56         {
 57             return base.OnReconnected();
 58         }
 59         #endregion
 60 
 61         /**************************************下面是自定义的服务器端方法*************************************************/
 62 
 63         #region 01-点对点发送消息
 64         /// 
 65         /// 点对点发送消息
 66         /// 
 67         /// 
 68         /// 
 69         public void SendSingleMsg(string receiveId, string msg)
 70         {
 71             Clients.Client(receiveId).receiveMsg($"用户【{this.Context.ConnectionId}】发来消息:{msg}");
 72         }
 73         #endregion
 74 
 75         #region 02-群发消息
 76         /// 
 77         /// 群发消息
 78         /// 
 79         /// 
 80         [HubMethodName(nameof(SendAllMsg))]
 81         public void SendAllMsg(string msg)
 82         {
 83             //除去自己以外的消息(不需要自己存储ConnectionId)
 84             Clients.AllExcept(this.Context.ConnectionId).receiveMsg($"用户【{this.Context.ConnectionId}】发来消息:{msg}");
 85         }
 86         #endregion
 87 
 88         #region 03-进入指定组
 89         /// 
 90         /// 进入指定组
 91         /// 
 92         /// 组的名称
 93         [HubMethodName(nameof(EnterRoom))]
 94         public void EnterRoom(string roomName)
 95         {
 96             //进入组
 97             Groups.Add(this.Context.ConnectionId, roomName);
 98             //告诉自己进入成功
 99             Clients.Client(this.Context.ConnectionId).receiveMsg($"用户【{this.Context.ConnectionId}】成功进入组:【{roomName}】");
100         }
101         #endregion
102 
103         #region 04-向指定组发送消息
104         /// 
105         /// 向指定组发送消息
106         /// 
107         /// 组名
108         /// 内容
109         [HubMethodName(nameof(SendRoomNameMsg))]
110         public void SendRoomNameMsg(string roomName, string msg)
111         {
112             //向指定组发送消息,如果这个组包含自己,将自己除外
113             Clients.Group(roomName, this.Context.ConnectionId).receiveMsg($"用户【{this.Context.ConnectionId}】发来消息:{msg}");
114         }
115         #endregion
116 
117     }
118 }

View Code

控制器代码

 1 using Microsoft.AspNet.SignalR;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Mvc;
 7 
 8 namespace HubDemo.Controllers
 9 {
10     /// 
11     /// Hub模型(中心模型)
12     /// 
13     /// 
14     public class HubController : Controller
15     {
16         #region 01-代理模式页面
17         /// 
18         /// 代理模式页面
19         /// 
20         /// 
21         public ActionResult Index()
22         {
23             return View();
24         }
25         #endregion
26 
27         #region 02-非代理模式页面
28         /// 
29         /// 非代理模式页面
30         /// 
31         /// 
32         public ActionResult NoProxyIndex()
33         {
34             return View();
35         }
36         #endregion
37 
38 
39 
40         /****************************************************下面是第三方调用方法****************************************************************/
41 
42 
43         #region 01-向所有人发送消息
44         /// 
45         /// 向所有人发送消息
46         /// 
47         /// 当前用户的登录标记
48         /// 发送的信息
49         public string MySendAll(string myConnectionId ,string msg)
50         {
51             //Hub模式
52             var hub = GlobalHost.ConnectionManager.GetHubContext();
53             hub.Clients.AllExcept(myConnectionId).receiveMsg($"用户【{myConnectionId}】发来消息:{msg}");
54             return "ok";
55         } 
56         #endregion
57 
58 
59 
60     }
61 }

View Code

代理

复制代码

  1 @{
  2     Layout = null;
  3 }
  4 
  5 
  6 
  7 
  8 
  9    
 10     
 11     Index
 12     
 13     
 14     
 15     
 16     
 17     @**@
 18     
 19         $(function () {
 20 
 21             //一. 初始化信息
 22             //默认路径
 23             //1. 与服务器路径进行匹配
 24             var conn = $.connection.hub;
 25             //2. 与生成的代理类建立连接
 26             var proxy = $.connection.mySpecHub1;
 27             //3.当服务器端指定路径的时候,需要有下面的代码进行匹配(仅使用手动代理)
 28             //conn.url = "/myhub1";
 29 
 30             //二. 定义客户端的方法
 31             //1 接受用户登录成功后的提示
 32             proxy.client.LoginSuccessNotice = function (data, connectionId) {
 33                 $("#j_Msg").append("
  • " + data + "
  • "); 34 35 }; 36 //2 接收点对点用户发送来的消息 37 proxy.client.receiveMsg = function (data) { 38 $("#j_Msg").append("
  • " + data + "
  • "); 39 } 40 //3. 接收自己的connectionId 41 proxy.client.ReceiveOwnCid = function (connectionId) { 42 //把用户ConnectionID存起来 43 $("#j_connectionId").val(connectionId); 44 } 45 46 47 //三. 主动事件 48 //1.建立连接 49 $("#j_connect").click(function () { 50 conn.start().done(function () { 51 $("#j_notice").html("连接成功"); 52 }).fail(function () { 53 console.log('Could not connect'); 54 }); 55 }); 56 //2.断开连接 57 $("#j_close").click(function () { 58 conn.stop(); 59 }); 60 //3.点对点发送消息 61 $("#j_send").click(function () { 62 var state = conn.state; 63 if (state == 1) { 64 //调用服务器端方法 65 proxy.server.sendSingleMsg($("#j_receiveId").val(), $("#j_content").val()); 66 } else if (state == 0) { 67 $("#j_notice").html("正在连接中,请稍等"); 68 } else if (state == 2) { 69 $("#j_notice").html("正在重连,请稍等"); 70 } else if (state == 4) { 71 $("#j_notice").html("掉线了,请重新连接"); 72 } 73 74 }); 75 //4.群发消息 76 $("#j_sendAll").click(function () { 77 var state = conn.state; 78 if (state == 1) { 79 //调用服务器端方法 80 proxy.server.SendAllMsg($("#j_content").val()); 81 } else if (state == 0) { 82 $("#j_notice").html("正在连接中,请稍等"); 83 } else if (state == 2) { 84 $("#j_notice").html("正在重连,请稍等"); 85 } else if (state == 4) { 86 $("#j_notice").html("掉线了,请重新连接"); 87 } 88 89 }); 90 //5.进入room1 91 $("#j_room1").click(function () { 92 //调用服务器端方法 93 proxy.server.EnterRoom("room1"); 94 }); 95 //6.进入room2 96 $("#j_room2").click(function () { 97 //调用服务器端方法 98 proxy.server.EnterRoom("room2"); 99 }); 100 //7. 给room1中的用户发送消息 101 $("#j_sendRoom1").click(function () { 102 proxy.server.SendRoomNameMsg("room1", $('#j_content2').val()); 103 }); 104 //8. 给room2中的用户发送消息 105 $("#j_sendRoom2").click(function () { 106 proxy.server.SendRoomNameMsg("room2", $('#j_content2').val()); 107 }); 108 109 //9. 调用控制器中的方法发送信息 110 $("#j_btn").click(function () { 111 var myConnectionId = $("#j_connectionId").val(); 112 var msg = $('#j_content3').val(); 113 console.log(myConnectionId); 114 $.post("/Hub/MySendAll", { myConnectionId: myConnectionId, msg: msg }, function (data) { 115 if (data == "ok") { 116 alert("发送成功"); 117 } 118 }); 119 120 }); 121 122 123 124 125 126 //四. 监控事件 127 //1. 连接断开的方法 128 conn.disconnected(function () { 129 $("#j_notice").html("连接中断"); 130 }); 131 132 133 134 135 }); 136 137 138 139
    140
    提示:
    141
    142 建立连接 143 关闭连接 144
    145
    146 147 148 单发 149 群发 150
    151
    152 进入room1 153 进入room2 154
    155
    156 157 给room1发送消息 158 给room2发送消息 159
    160
    161 162 调用控制器中的方法 163
    164
    165
      166
      167
      168 169 170

      复制代码

      View Code

      非代理

        1 @{
        2     Layout = null;
        3 }
        4 
        5 
        6 
        7 
        8 
        9    
       10     
       11     Index
       12     
       13     
       14     
       15         $(function () {
       16 
       17 
       18             //一. 初始化信息
       19             //默认路径
       20             //1. 与服务器路径进行匹配
       21             var conn = $.hubConnection();
       22             //2. 手动创建代理类
       23             var proxy = conn.createHubProxy("MySpecHub1");
       24 
       25 
       26             //指定路径
       27             1. 与服务器路径进行匹配
       28             //var conn = $.hubConnection("/myhub1", { useDefaultPath: false }); //对应的路径为"/myhub1"
       29             //var conn = $.hubConnection("/myhub1");   //对应的路径为"/myhub1/signalr"
       30             2. 手动创建代理类
       31             //var proxy = conn.createHubProxy("MySpecHub1");
       32 
       33 
       34             //二. 定义客户端的方法
       35             //1 接受用户登录成功后的提示
       36             proxy.on("LoginSuccessNotice", function (data, connectionId) {
       37                 $("#j_Msg").append("
    • " + data + "
    • "); 38 }); 39 //2 接收点对点用户发送来的消息 40 proxy.on("receiveMsg", function (data) { 41 $("#j_Msg").append("
    • " + data + "
    • "); 42 }); 43 //3. 接收自己的connectionId 44 proxy.on("ReceiveOwnCid", function (connectionId) { 45 //把用户ConnectionID存起来 46 $("#j_connectionId").val(connectionId); 47 }); 48 49 50 51 //三. 主动事件 52 //1.建立连接 53 $("#j_connect").click(function () { 54 conn.start().done(function () { 55 $("#j_notice").html("连接成功"); 56 }).fail(function () { 57 console.log('Could not connect'); 58 }); 59 }); 60 //2.断开连接 61 $("#j_close").click(function () { 62 conn.stop(); 63 }); 64 65 //3.点对点发送消息 66 $("#j_send").click(function () { 67 var state = conn.state; 68 if (state == 1) { 69 //调用服务器端方法 70 proxy.invoke("SendSingleMsg", $("#j_receiveId").val(), $("#j_content").val()); 71 } else if (state == 0) { 72 $("#j_notice").html("正在连接中,请稍等"); 73 } else if (state == 2) { 74 $("#j_notice").html("正在重连,请稍等"); 75 } else if (state == 4) { 76 $("#j_notice").html("掉线了,请重新连接"); 77 } 78 79 }); 80 //4.群发消息 81 $("#j_sendAll").click(function () { 82 var state = conn.state; 83 if (state == 1) { 84 //调用服务器端方法 85 proxy.invoke("SendAllMsg", $("#j_content").val()); 86 } else if (state == 0) { 87 $("#j_notice").html("正在连接中,请稍等"); 88 } else if (state == 2) { 89 $("#j_notice").html("正在重连,请稍等"); 90 } else if (state == 4) { 91 $("#j_notice").html("掉线了,请重新连接"); 92 } 93 94 }); 95 96 //5.进入room1 97 $("#j_room1").click(function () { 98 //调用服务器端方法 99 proxy.invoke("EnterRoom", "room1"); 100 }); 101 //6.进入room2 102 $("#j_room2").click(function () { 103 //调用服务器端方法 104 proxy.invoke("EnterRoom", "room2"); 105 }); 106 //7. 给room1中的用户发送消息 107 $("#j_sendRoom1").click(function () { 108 proxy.invoke("SendRoomNameMsg", "room1", $('#j_content2').val()); 109 }); 110 //8. 给room2中的用户发送消息 111 $("#j_sendRoom2").click(function () { 112 proxy.invoke("SendRoomNameMsg", "room2", $('#j_content2').val()); 113 }); 114 115 //9. 调用控制器中的方法发送信息 116 $("#j_btn").click(function () { 117 var myConnectionId = $("#j_connectionId").val(); 118 var msg = $('#j_content3').val(); 119 console.log(myConnectionId); 120 $.post("/Hub/MySendAll", { myConnectionId: myConnectionId, msg: msg }, function (data) { 121 if (data == "ok") { 122 alert("发送成功"); 123 } 124 }); 125 126 }); 127 128 129 130 131 //四. 监控事件 132 //1. 连接断开的方法 133 conn.disconnected(function () { 134 $("#j_notice").html("连接中断"); 135 }); 136 137 138 //五. 其它事件 139 140 141 }); 142 143 144 145
      146
      提示:
      147
      148 建立连接 149 关闭连接 150
      151
      152 153 154 单发 155 群发 156
      157
      158 进入room1 159 进入room2 160
      161
      162 163 给room1发送消息 164 给room2发送消息 165
      166
      167 168 调用控制器中的方法 169
      170
      171
        172
        173
        174 175 176

        View Code

         

          PS:SignalR 与WebSocket原生代码编写的相比较,最大的改进之处有:

          ①:单发和群发可以对应不同的服务器端方法,不再需要自行约定规则来识别了,同样客户端接收也很灵活了,可以指定方法接收。

          ②:不需要自己创建登录标记,默认会生成一个ConnectionId。

          ③:ConnectionId会自动记录,不需要单独声明一个集合来存储。

          ④:写起来太爽了(^_^)。

          

         

        转载:https://www.cnblogs.com/yaopengfei/p/9304308.html

        关注
        打赏
        1660814979
        查看更多评论
        立即登录/注册

        微信扫码登录

        0.0413s