• SignalR实现消息推送,包括私聊、群聊、在线所有人接收消息(源码)


    一、关于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类,(如果创建项目是有这个类。就不用添加了)添加代码如下 

    1
    2
    3
    4
    5
    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;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="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 里面有更多的开源项目哦,欢迎加入讨论

    如果你还满意请点击关注和推荐,谢谢    

  • 相关阅读:
    第一节:从程序集的角度分析System.Web.Caching.Cache ,并完成基本封装。
    大话缓存
    第二节:SQLServer的安装及使用
    OpenCV特征点检测——ORB特征
    Opencv学习笔记--Harris角点检测
    关于Yuri Boykov and Vladimir Kolmogorov 于2004年提出的max flow / min cut的算法的详解
    [论文笔记] CUDA Cuts: Fast Graph Cuts on the GPU
    Graph Cut and Its Application in Computer Vision
    OpenCV中openMP的使用
    四种简单的图像显著性区域特征提取方法-----> AC/HC/LC/FT。
  • 原文地址:https://www.cnblogs.com/webenh/p/7810434.html
Copyright © 2020-2023  润新知