zoukankan      html  css  js  c++  java
  • C# SignalR 即时通讯 聊天室

    一.SignalR简介

    SignalR:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。实现实时服务器与客户端通信。是一个开源.NET 库生成需要实时用户交互或实时数据更新的 web 应用程序。

    SignalR的出现,让页面通过javascript可以很简单的调用后端服务的方法,而在后端也可以很简单的直接调用javascript所实现的方法,前后端可以进行实时通信。实现了服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请求或使用轮询技术来获取消息。

    注意:SignalR 会自动管理连接。客户端和服务器之间的连接是持久性的,不像传统的 HTTP 连接。

    二.SignalR传输方式

    SignalR会根据当前浏览器自动选择适当的传输方式。在最坏的情况下,SignalR会选择使用长轮询(Long Polling).

    SignalR会依照下列顺序来判定使用那种传输方式:

    • 1.如果浏览器是 Internet Explorer8 或更早版本,则使用长轮询。
    • 2.如果配置了 JSONP(即连接启动时 jsonp 参数设置为 true),则使用长轮询。
    • 3.如果要建立跨域连接(即 SignalR 终结点和宿主页不在相同的域中),并且满足以下条件,则会使用 WebSocket:
      • 3.1客户端支持 CORS(跨域资源共享)
      • 3.2客户端支持 WebSocket
      • 3.3服务器支持 WebSocket
      • 如果这些条件中的任何一条不满足,将使用长轮询.
    • 4.如果未配置 JSONP 并且连接没有跨域,只要客户端和服务器都支持的话,将使用 WebSocket。
    • 5.如果客户端或服务器不支持 WebSocket,则尽量使用服务器发送事件。Forever Frame。
    • 7.如果 Forever Frame 失败,则使用长轮询。

    长轮询(long polling)与传统Ajax的不同之处:

    • 1.服务器端会阻塞请求直到有数据传递或超时才返回。
    • 2.客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
    • 3.当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取回。

    三.SignalR使用(个人理解)

    下面是聊天室的主要代码:

    C#代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    //工具 -> 库程序包管理器 -> 程序包管理器控制台 输入下面命令  
    //install-package Microsoft.AspNet.SignalR -Version 1.1.4  
    using Microsoft.AspNet.SignalR;
    using System.Threading.Tasks;
    using Microsoft.AspNet.SignalR.Hubs;
    
    namespace SignalR.Controllers
    {
        [HubName("ChatRoomHub")]
        public class ChatHub : Hub
        {
            static List<UserEntity> users = new List<UserEntity>();
    
            /// <summary>
            /// 添加用户
            /// </summary>
            /// <param name="nickName"></param>
            public void UserEnter(string nickName)
            {
                UserEntity userEntity = new UserEntity
                {
                    NickName = nickName,
                    ConnectionId = Context.ConnectionId
                };
    
                users.Add(userEntity);
                Clients.All.NotifyUserEnter(nickName, users);//调用前台NotifyUserEnter方法
            }
    
            /// <summary>
            /// 发送消息
            /// </summary>
            /// <param name="nickName"></param>
            /// <param name="message"></param>
            public void SendMessage(string nickName, string message)
            {
                Clients.All.NotifySendMessage(nickName, message);//调用前台NotifySendMessage方法
            }
    
            /// <summary>
            /// 断开(刷新页面可以触发此方法)
            /// </summary>
            /// <returns></returns>
            public override Task OnDisconnected()
            {
                var currentUser = users.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId);
                if (currentUser != null)
                {
                    users.Remove(currentUser);
                    Clients.Others.NotifyUserLeft(currentUser.NickName, users);//调用前台NotifyUserLeft方法
                }
                return base.OnDisconnected();
            }
        }
    
        public class UserEntity
        {
            public string NickName { get; set; }
    
            public string ConnectionId { get; set; }
        }
    
    
        public class BaseController : Controller
        {
    /// <summary> /// 聊天室 /// </summary> /// <returns></returns> public ActionResult BroadcastTest() { return View(); } } }

    前台主要JavaScript代码:

        <script type="text/javascript">
            var userNickName;//昵称
            var notification;//消息
    
            jQuery(document).ready(function () {
                //没有用户名弹出输入框
                while (!userNickName) {
                    userNickName = window.prompt("请输入昵称!");
                }
    
                var chatHub = $.connection.ChatRoomHub;//对应后台的类ChatHub
    
                //添加用户
                chatHub.client.NotifyUserEnter = function (nickName, users) {
                    buildUserTemplate(users);
                }
    
                //用户离开
                chatHub.client.NotifyUserLeft = function (nickName, users) {
                    buildUserTemplate(users);
                }
    
                //处理消息内容
                chatHub.client.NotifySendMessage = function (nickName, message) {
                    var userAvatar = 'http://forum.csdn.net/PointForum/ui/scripts/csdn/Plugin/001/face/29.gif';
                    //判断消息归属
                    if (nickName == userNickName) {
                        $("#div_msg").append("<div style='text-align:right;'>"
                        + "<div float:right> <span style='margin-right:10px'>" + nickName + "</span>"
                         + "<img src='" + userAvatar + "' style='height:30px;30px;position:relative'/>"
                        + "<div class='demo clearfix fr'>"
                        + "<span class='triangle'></span>"
                        + "<div class='article' style='word'>" + message
                        + "</div></div></div></div><div class='clear-float'/>");
                    }
                    else {
                        $("#div_msg").append("<div>"
                         + "<img src='" + userAvatar + "' style='height:30px;30px;position:relative'/>"
                         + "<span style='left:10px;position:relative'>" + nickName + "</span>"
                         + "<div class='demo clearfix'>"
                         + "<span class='triangle'></span>"
                         + "<div class='article'>" + message
                         + "</div></div></div>");
                    }
                    //消息弹出框
                    if (Notification.permission == "granted") {
                        notification = new Notification(nickName, {
                            body: message,
                            icon: userAvatar,
                            renotify: true,
                            tag: 1,
                            noscreen: true
                        });
    
                        notification.onclick = function () {
                            notification.close();
                        };
                    } else if (Notification.permission != "denied") {
                        Notification.requestPermission(function (permission) {
                            notification = new Notification(nickName, {
                                body: message,
                                icon: userAvatar,
                                renotify: true,
                                tag: 1,
                                noscreen: true
                            });
    
                            notification.onclick = function () {
                                notification.close();
                            };
                        });
                    }
                    var objDiv = document.getElementById("div_msgbody");
                    objDiv.scrollTop = objDiv.scrollHeight;
                }
    
                $.connection.hub.start().done(function () {
                    chatHub.server.userEnter(userNickName);
                });
    
                //聊天框发送消息
                $("#message").keydown(function (event) {
                    if (event.keyCode == 13) {
                        if ($("#message").val() != "") {
                            chatHub.server.sendMessage(userNickName, $("#message").val());
                            $("#message").val("");
                        }
                    }
                });
    
                //发送按钮
                $("#btn_Send").click(function () {
                    if ($("#message").val() != "") {
                        chatHub.server.sendMessage(userNickName, $("#message").val());
                        $("#message").val("");
                    }
                });
    
                //用户列表
                function buildUserTemplate(users) {
                    $("#lab_total").text(users.length);
                    var userTemplate = "<ul style='list-style:none;'>"
                    $.each(users, function (e, v) {
                        var userAvatar = 'http://forum.csdn.net/PointForum/ui/scripts/csdn/Plugin/001/face/29.gif';
                        userTemplate += "<li style='padding-top:5px;'>"
                            + "<img class='round-img-list' src='" + userAvatar + "'/>"
                            + "<label style='color:#666666;margin-left:10px'>" + v.NickName + "</label>"
                            + "</li>";
                    });
    
                    userTemplate += "</ul>";
    
                    $("#div_member").html(userTemplate);
                }
            });
        </script>

    完整SignalR的源码(包括聊天室,进度条)(我用的vs2013):

    百度网盘:链接: https://pan.baidu.com/s/1gf7s5oB 密码: mdi2

    最后:

      1、Clients.All.NotifySendMessage(nickName, message);调用的是前台JschatHub.client.NotifySendMessage = function (nickName, message) {}这段代码。

      2、javascript中,注意使用client和server关键字来调用前端方法和后端方法。

    聊天室例子:

    下面是进度条例子:

    广播例子:


    相关文章:http://www.cnblogs.com/frozenzhang/p/5406773.html

  • 相关阅读:
    机器学习(十七)— SVD奇异值分解
    机器学习(十五)— Apriori算法、FP Growth算法
    机器学习(十四)— kMeans算法
    深度学习—反卷积的理解
    【ECMAScript5】ECMAScript5中有关数组的常用方法
    【window】window10永久关闭更新
    【js】使用javascript 实现静态网页分页效果
    【vue】钩子函数生命周期
    【vue】vue中ref用法
    【vue-waring】element UI 由版本1.4.12 升级到element-ui@2.0.10
  • 原文地址:https://www.cnblogs.com/cang12138/p/7404124.html
Copyright © 2011-2022 走看看