暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

Net分享 2021-09-01
3131

一、关于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,如图

  

    并编写以下代码

public class ServerHub : Hub
    {
        private static readonly char[] str =
        {
            '0''1''2''3''4''5''6''7''8''9',
            'a''b''c''d''e''f''g''h''i''j''k''l''m''n''o''p''q''r''s''t''u''v',
            'w''x''y''z',
            'A''B''C''D''E''F''G''H''I''J''K''L''M''N''O''P''Q''R''S''T''U''V',
            'W''X''Y''Z'
        };

        /// <summary>
        /// 消息发送接口
        /// </summary>
        /// <param name="message"></param>
        public void SendMsg(string message)
        {
            var name = GenerateUserName(4);

            // 调用所有客户端的sendMessage方法
            Clients.All.sendMessage(name, message);
        }

        /// <summary>
        /// 产生随机用户
        /// </summary>
        /// <param name="length">用户名长度</param>
        /// <returns></returns>
        public static string GenerateUserName(int length)
        {
            var newRandom = new StringBuilder(62);
            var rd = new Random();
            for (var i = 0; i < length; i++)
            {
                newRandom.Append(str[rd.Next(62)]);
            }
            return newRandom.ToString();
        }

复制
 
复制

    (2)、创建一个Startup类,(如果创建项目是有这个类。就不用添加了)添加代码如下

public void Configuration(IAppBuilder app)
       {
           // 配置集线器
           app.MapSignalR();
       }

复制

     (3)、添加Home控制器及视图Index(此步骤不截图)

   (4)、添加Index视图代码  如下

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
    ViewBag.Title = "聊天窗口";
}

<h2>Index</h2>

<div class="container">
    <input type="text" id="message" />
    <input type="button" id="sendmessage" value="Send" />
    <input type="hidden" id="displayname" />
    <ul id="discussion"></ul>
</div>

@section scripts
{
<script src="~/Scripts/jquery-1.6.4.min.js"></script>
    <!--引用SignalR库. -->
    <script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>
    <!--引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 -->
    <script src="~/signalr/hubs"></script>

    <script>
        $(function () {
            // 引用集线器代理
            var chat = $.connection.serverHub;
            // 定义服务器端调用的客户端sendMessage来显示新消息

            chat.client.sendMessage = function (name, message) {
                // 向页面添加消息
                $('#discussion').append('<li><strong>' + htmlEncode(name)
                    + '</strong>: ' + htmlEncode(message) + '</li>');
            };

            // 设置焦点到输入框
            $('#message').focus();
            // 开始连接服务器
            $.connection.hub.start().done(function () {
                $('#sendmessage').click(function () {
                    // 调用服务器端集线器的SendMsg方法
                    chat.server.sendMsg($('#message').val());
                    // 清空输入框信息并获取焦点
                    $('#message').val('').focus();
                });
            });
        });

        // 为显示的消息进行Html编码
        function htmlEncode(value) {
            var encodedValue = $('<div />').text(value).html();
            return encodedValue;
        }
    </script>
}

复制


  4、完成以上步骤之后,我们的SignalR算是简单的完成。让我们来看下制作结果吧

    (1)、如果出现如下错误,请删除红框里的代码

    

    成功之后的结果,如图

    

    你以为完了嘛?还没有,别急往下看

三、页面有优化及私聊、群聊、在线所有人接收消息的实现

  1、发送所有在线人员

    (1)、在layer官网下载layer前端js和ui(在我上一篇的文章中有下载地址,或者直接百度搜索layer),放到你的项目中,在这里我们就不直接说页面代码的编写部分,直接看下我们的效果图,如下

     

    (2)、在完成聊天之前。我们还需要做什么,对做登录,在这里自动生成的用户已经不能满足我们接下来的需求了(登录教程跳过)直接看登录成功过后的界面

    

    

    这样看起来就美观多了,其实在线所有人聊天的功能,就是刚刚我们实现那个功能是一样的,没有任何的变化(只是美观了下),看看聊天结果吧

    

      

  

    2、群聊

      (1)、首先我们的建一个群聊的实体(UserGroup)和房间实体(ChatRoom),如下图

       

    (2)、在我们建好的ServerHub类里编写如下代码(具体实现看源码)

public static ChatContext DbContext = new ChatContext();

        // 重写Hub连接断开的事件  (断线时调用)
        public override Task OnDisconnected(bool stopCalled)
        {
            // 查询用户
            var user = DbContext.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);

            if (user != null)
            {
                // 删除用户
                DbContext.Users.Remove(user);

                // 从房间中移除用户
                foreach (var item in user.Rooms)
                {
                    RemoveUserFromRoom(item.RoomName);
                }
            }
            return base.OnDisconnected(stopCalled);
        }

        // 为所有用户更新房间列表
        public void UpdateRoomList()
        {
            var itme = DbContext.Rooms.Select(p => new { p.RoomName });
            var jsondata = JsonHelper.ToJsonString(itme.ToList());
            Clients.All.getRoomlist(jsondata);
        }

        /// <summary>
        /// 加入聊天室
        /// </summary>
        public void JoinRoom(string roomName)
        {
            // 查询聊天室
            var room = DbContext.Rooms.Find(p => p.RoomName == roomName);

            // 存在则加入
            if (room == null) return;

            // 查找房间中是否存在此用户
            var isExistUser = room.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);

            // 不存在则加入
            if (isExistUser == null)
            {
                var user = DbContext.Users.Find(u => u.UserId == Context.ConnectionId);
                user.Rooms.Add(room);
                room.Users.Add(user);

                // 将客户端的连接ID加入到组里面
                Groups.Add(Context.ConnectionId, roomName);

                //调用此连接用户的本地JS(显示房间)
                Clients.Client(Context.ConnectionId).joinRoom(roomName);
            }
            else
            {
                Clients.Client(Context.ConnectionId).showMessage("请勿重复加入房间!");
            }
        }

        /// <summary>
        /// 创建聊天室
        /// </summary>
        /// <param name="roomName"></param>
        public void CreateRoom(string roomName)
        {
            var room = DbContext.Rooms.Find(a => a.RoomName == roomName);
            if (room == null)
            {
                var cr = new ChatRoom
                {
                    RoomName = roomName
                };

                //将房间加入列表
                DbContext.Rooms.Add(cr);

                // 本人加入聊天室
                JoinRoom(roomName);
                UpdateRoomList();
            }
            else
            {
                Clients.Client(Context.ConnectionId).showMessage("房间名重复!");
            }
        }

        public void RemoveUserFromRoom(string roomName)
        {
            //查找房间是否存在
            var room = DbContext.Rooms.Find(a => a.RoomName == roomName);

            //存在则进入删除
            if (room == null)
            {
                Clients.Client(Context.ConnectionId).showMessage("房间名不存在!");
                return;
            }

            // 查找要删除的用户
            var user = room.Users.FirstOrDefault(a => a.UserId == Context.ConnectionId);
            // 移除此用户
            room.Users.Remove(user);
            //如果房间人数为0,则删除房间
            if (room.Users.Count <= 0)
            {
                DbContext.Rooms.Remove(room);
            }

            Groups.Remove(Context.ConnectionId, roomName);

            //提示客户端
            Clients.Client(Context.ConnectionId).removeRoom("退出成功!");
        }

        /// <summary>
        /// 给房间内所有的用户发送消息
        /// </summary>
        /// <param name="room">房间名</param>
        /// <param name="message">信息</param>
        public void SendMessage(string room, string message)
        {
            // 调用房间内所有客户端的sendMessage方法
            // 因为在加入房间的时候,已经将客户端的ConnectionId添加到Groups对象中了,所有可以根据房间名找到房间内的所有连接Id
            // 其实我们也可以自己实现Group方法,我们只需要用List记录所有加入房间的ConnectionId
            // 然后调用Clients.Clients(connectionIdList),参数为我们记录的连接Id数组。
            Clients.Group(room, new string[0]).sendMessage(room, message + " " + DateTime.Now);
        }

复制
(3)、在Home控制器里创建GroupUser视图并添加如下代码
复制
 
复制
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
    <script src="~/Scripts/layer/layer.js"></script>
    <!--这里要注意,这是虚拟目录,也就是你在OWIN Startup中注册的地址-->
    <script src="/signalr/hubs"></script>

    <script type="text/javascript">
        var chat;
        var roomcount = 0;

        $(function() {
            chat = $.connection.serverHub;
            chat.client.showMessage = function(message) {
                alert(message);
            };
            chat.client.sendMessage = function(roomname, message) {
                $("#" + roomname).find("ul").each(function() {
                    $(this).append('<li>' + message + '</li>');
                });
            };
            chat.client.removeRoom = function(data) {
                alert(data);
            };
            chat.client.joinRoom = function (roomname) {
                var html = '<div style="float:left; margin-left:360px; border:double; height:528px;width:493px" id="' + roomname + '" roomname="' + roomname + '"><button onclick="RemoveRoom(this)">退出</button>\
                                    '
 + roomname + '房间\
                                                聊天记录如下:<ul>\
                                                </ul>\
                                    <textarea class="ChatCore_write" id="ChatCore_write" style="width:400px"></textarea> <button onclick="SendMessage(this)">发送</button>\
                                    </div>'
;
                $("#RoomList").append(html);
            };

            //注册查询房间列表的方法
            chat.client.getRoomlist = function(data) {
                if (data) {
                    var jsondata = $.parseJSON(data);
                    $("#roomlist").html(" ");
                    for (var i = 0; i < jsondata.length; i++) {
                        var html = ' <li>房间名:' + jsondata[i].RoomName + '<button roomname="' + jsondata[i].RoomName + '" onclick="AddRoom(this)">加入</button></li>';
                        $("#roomlist").append(html);
                    }
                }
            };
            // 获取用户名称。
            $('#username').html(prompt('请输入您的名称:'''));

            $.connection.hub.start().done(function() {
                $('#CreatRoom').click(function() {
                    chat.server.createRoom($("#Roomname").val());
                });
            });
        });

        function SendMessage(btn) {
            var message = $(btn).prev().val();
            var room = $(btn).parent();
            var username = $("#username").html();
            message = username + ":" + message;
            var roomname = $(room).attr("roomname");
            chat.server.sendMessage(roomname, message);
            $(btn).prev().val('').focus();
        }

        function RemoveRoom(btn) {
            var room = $(btn).parent();
            var roomname = $(room).attr("roomname");
            chat.server.removeUserFromRoom(roomname);
        }

        function AddRoom(roomname) {
            var data =$(roomname).attr("roomname");
            chat.server.joinRoom(data);
        }

    </script>
</head>
<body>
    <div>
        <div>名称:<p id="username"></p></div>
        输入房间名:
        <input type="text" value="聊天室1" id="Roomname" />
        <button id="CreatRoom">创建聊天室</button>
    </div>
    <div style="float:left;border:double">
        <div>房间列表</div>
        <ul id="roomlist"></ul>
    </div>
    <div id="RoomList">
    </div>
</body>
</html>

复制

    (4)、做好以上步骤之后,主要的功能已经实现,那么接下来我们看下效果 如下

    点击发送群聊之后出现如图所示

    

    并创建自己的用户名

    我们在创建自己的用户名之后,可以选择自己创建房间或者加入已有的房间,如下图

    

    

  3、私聊

    (1)、私聊我们在这里就不多说了。实现原理和群里差不多。都是找到对应的人员id就ok,直接上图看结果

    

    

>https://www.cnblogs.com/cyzf/p/7808798.html




复制

C# 利用PdfSharp生成Pdf文件

Topshelf 搭建 Windows 服务

C# 中的单元测试

修改Nuget包默认存放路径

读取appsetting.json的两种方式
C#和sql 中的 四舍五入向下向上取整

C#中Contains, Exists, Any

控制台程序发布为windows服务

ASP.NET Core可视化日志组件使用

.NET Core 下使用 Serilog 记录日志

Entity Framework Core必须牢记的三条引用三条命令

C#中IOC容器-Autofac的使用

复制



文章转载自Net分享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论