什么是ASP.NET SignalR?

ASP.NET SignalR是一个方便程序员添加实时网络通信功能的类库。所谓的实时网络通信功能(Real-time Web Functionality)就是需要服务器主动推送数据到用户客户端,而非服务器等待用户客户端请求数据的功能。以聊天室为例,当一个用户发送群发消息之后,在所有用户的聊天窗口中都需要显示出这条消息,如果每个用户客户端都是用Ajax每隔一定时间去服务器上拉取消息,那样不仅效率低下并增加服务器负担,也不是真正意义上的实时程序。

消息传输机制

ASP.Net SignalR使用新的Websocket传输协议,他实现了浏览器和服务器全双工通信(允许服务器主动发消息给客户端),并兼容以前的长连接(Long poll)传输方式, 所以对于开发人员来说,不需要自己去维护使用何种传输方式,SignalR会自动根据客户端浏览器的版本自动切换消息传输方式

  • 对于IE8,会自动切换到Long poll传输。
  • 对于IE9及以上版本,会使用Websocket传输。

连接与枢纽

SignalR API包含2个模型来帮助客户端与服务器进行通信: 持久连接(Persistent Connections)与枢纽 (hubs).

持久连接负责传输消息,枢纽提供了一种很有趣的机制,允许开发人员在客户端调用服务器端方法或服务器端调用客户端方法。

枢纽(Hubs)是如何工作的

当服务器端程序调用客户端方法时,一个包含客户端方法名及参数的Json数据包会通过持久连接传输到客户端,客户端会根据数据包中的方法名进行匹配,如果找到相同方法名的方法,就会自动调用找到的方法,方法所需的参数值会使用数据包中对应的参数值。

简单的聊天室

下面用一个聊天室的例子,熟悉一下SignalR的基本使用方式。

这个聊天室页面的需求如下:

  1. 用户打开聊天室页面,需要首先录入自己的昵称,输入昵称之后,通知聊天室的其他用户该用户进入聊天室
  2. 用户可以使用在聊天室中发送公共消息
  3. 用户可以使用“to 用户名 消息内容”的方式发送私聊消息

添加项目

新建一个空的ASP.NET Web Application工程


通过Nuget或者最新版本的SignalR库

展开Package Manager Console面板,输入

install-package Microsoft.AspNet.SignalR

添加Startup.cs启用SignalR

using Microsoft.Owin;

using Owin;

 

[assembly: OwinStartup(typeof(ChatRoom.Startup))]

 

namespace ChatRoom

{

    public class Startup

    {

        public void Configuration(IAppBuilder app)

        {

            //启用SignalR

            app.MapSignalR();

        }

    }

}

添加枢纽(Hub)

在工程中添加ChatRoomHub.cs, 选择SignalR Hub Class(v2)

替换ChatRoomHub类中的内容替换

using Microsoft.AspNet.SignalR;

using System.Collections.Generic;

using System.Linq;

 

namespace ChatRoom

{

    public class ChatRoomHub : Hub

    {

        private static Dictionary<string, string> _nickNames = new Dictionary<string, string>();

 

        public void SetNickName(string nickName)

        {

            //当Hub启动完毕,每个连接到这个Hub的客户端都会自动分配一个唯一的ConnectionId。

            //当SignalR向指定客户端推送消息的时候,需要指定ConnectionId, 所以这里需要记录一下每个昵称对应的客户端ConnectionId

            _nickNames.Add(Context.ConnectionId, nickName);

 

            //当用户设置昵称之后,需要发送欢迎信息到所有的用户客户端,调用客户端receiveWelcomeMessage方法显示欢迎信息

            Clients.All.ReceiveWelcomeMessage($"{nickName}进入聊天室。");

        }

 

        public void Send(string nickName, string message)

        {

            if (string.IsNullOrWhiteSpace(nickName) || string.IsNullOrWhiteSpace(message))

            {

                //如果用户昵称或者消息不存在,就不做任何操作

                return;

            }

 

            if (message.StartsWith("to") && message.Split(' ').Length == 3)

            {

                //私聊消息

                var toUserName = message.Split(' ')[1];

 

                if (_nickNames.ContainsValue(toUserName))

                {

                    var connectionId = _nickNames.First(p => p.Value == toUserName).Key;

 

                    if (!string.IsNullOrWhiteSpace(connectionId) && connectionId != Context.ConnectionId)

                    {

                        Clients.Client(connectionId).ReceivePrivateMessage(nickName, message.Split(' ')[2]);

                    }

                }

            }

            else

            {

                //普通广播消息

                if (_nickNames.ContainsValue(nickName))

                {

                    Clients.All.ReceiveBroadcastMessage(nickName, message);

                }

            }

        }

    }

}

添加显示页面

添加空html文件ChatRoom.html, 使用以下文件替换

<!DOCTYPE html>

<html>

<head>

    <title>SignalR Simple Chat</title>

    <style type="text/css">

        .container {

            background-color: #99CCFF;

            border: thick solid #808080;

            padding: 20px;

            margin: 20px;

        }

    </style>

</head>

<body>

    <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>

    <script src="Scripts/jquery-1.6.4.min.js"></script>

    <script src="Scripts/jquery.signalR-2.2.2.min.js"></script>

    <script src="signalr/hubs"></script>

 

    <script type="text/javascript">

        $(function () {

 

            //使用代理模式, 创建客户端的hub代理

            var chat = $.connection.chatRoomHub;

 

            //服务器Hub中, 调用ReceiveWelcomeMessage方法时, 会执行客户端的chat.client.receiveBroadcastMessage方法

            chat.client.receiveBroadcastMessage = function (name, message) {

 

                //防JS输入

                var encodedName = $('<div />').text(name).html();

                var encodedMsg = $('<div />').text(message).html();

 

                $('#discussion').append('<li><strong>' + encodedName

                    + '</strong>:  ' + encodedMsg + '</li>');

            };

 

            //服务器Hub中, 调用ReceiveWelcomeMessage方法时, 会执行客户端的chat.client.receiveWelcomeMessage方法

            chat.client.receiveWelcomeMessage = function (message) {

                var encodedMsg = $('<div />').text(message).html();

 

                $('#discussion').append('<li><strong style="color:blue">' + encodedMsg

                    + '</strong></li>');

            };

 

            //服务器Hub中, 调用ReceivePrivateMessage方法时, 会执行客户端的chat.client.receivePrivateMessage方法

            chat.client.receivePrivateMessage = function (name, message) {

                var encodedName = $('<div />').text(name).html();

                var encodedMsg = $('<div />').text(message).html();

 

                $('#discussion').append('<li><strong style="color: green">' + encodedName

                    + '偷偷的跟你说</strong>:  ' + encodedMsg + '</li>');

            };

 

            //通过代理连接到服务器Hub

            $.connection.hub.start().done(function () {

                $('#sendmessage').click(function () {

                    chat.server.send($('#displayname').val(), $('#message').val());

 

                    $('#message').val('').focus();

                });

 

                //连接成功后, 需要用户立刻输入昵称

                $('#displayname').val(prompt('Enter your name:', ''));

                chat.server.setNickName($('#displayname').val());

                $('#message').focus();

            });

        });

    </script>

</body>

</html>

最终实现效果

SignalR学习笔记(一) 简单聊天室的更多相关文章

  1. Asp.Net SignalR - 简单聊天室实现

    简单聊天室 使用持久链接类我们就可以做一些即时通讯的应用了,我使用Group做了一个简单的聊天室,先上图技术细节下面再讲 可以加入聊天室.创建聊天室.发送消息,下面就说说我是如何通过Group做出来的 ...

  2. 简单聊天室(java版)

    这是本人从其他地方学习到的关于聊天室的一个模本,我从中截取了一部分关于客户端和服务端通信的Socket的内容.希望对大家对socket有个了解,我写的这些代码可以实现两人或多人在多台电脑上实现简单的对 ...

  3. JSP学习笔记(三):简单的Tomcat Web服务器

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

  4. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

  5. Python Socket 简单聊天室2

    上篇文章写了一个简单的单线程的一问一答的简单聊天室.这次我们使用SocketServer模块搭建一个多线程异步的聊天室. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...

  6. SignalR学习笔记(二)高并发应用

    虽然SignalR借助Websocket提供了很强大的实时通讯能力,但是在有些实时通讯非常频繁的场景之下,如果使用不当,还是会导致服务器,甚至客户端浏览器崩溃. 以下是一个实时拖拽方块项目的优化过程 ...

  7. SpringBoot 搭建简单聊天室

    SpringBoot 搭建简单聊天室(queue 点对点) 1.引用 SpringBoot 搭建 WebSocket 链接 https://www.cnblogs.com/yi1036943655/p ...

  8. ASP.NET SingalR + MongoDB 实现简单聊天室(一):搭建基本框架

    ASP.NET SingalR不多介绍.让我介绍不如看官网,我这里就是直接上源代码,当然代码还是写的比较简单的,考虑的也少,希望各位技友多多提意见. 先简单介绍聊天室功能: 用户加入聊天室,自动给用户 ...

  9. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...

  10. JAVA WEB学习笔记(三):简单的基于Tomcat的Web页面

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

随机推荐

  1. C - Thief in a Shop - dp完全背包-FFT生成函数

    C - Thief in a Shop 思路 :严格的控制好k的这个数量,这就是个裸完全背包问题.(复杂度最极端会到1e9) 他们随意原来随意组合的方案,与他们都减去 最小的 一个 a[ i ] 组合 ...

  2. BZOJ.4145.[AMPPZ2014]The Prices(状压DP)

    BZOJ 比较裸的状压DP. 刚开始写麻烦惹... \(f[i][s]\)表示考虑了前\(i\)家商店,所买物品状态为\(s\)的最小花费. 可以写求一遍一定去\(i\)商店的\(f[i]\)(\(f ...

  3. BZOJ5465 : [APIO 2018] 选圆圈

    假设最大的圆半径为$R$,以$2R$为大小将地图划分为一个个格子,那么每个圆只需要检查圆心在附近$9$个格子内部的所有圆. 在当前圆的半径不足$\frac{R}{2}$时重构网格,那么最多重构$O(\ ...

  4. 马昕璐/唐月晨 《面向对象程序设计(java)》第十一周学习总结

    一:理论部分. 一般将数据结构分为两大类:线性数据结构和非线性数据结构 线性数据结构:线性表.栈.队列.串.数组和文件 非线性数据结构:树和图. 线性表:1.所有数据元素在同一个线性表中必须是相同的数 ...

  5. zuoye

    a=input('请输入一个数字:') b=input('请再输入一个数字') sum2=int(a)+int(b) print('两个数字的和是:{}'.format(sum2)) a=input( ...

  6. 浅谈微信小程序一二

    1.生命周期 1.onLoad():页面加载时触发,一个页面只加载一次. 2.onShow():页面显示切换的时候触发 3.onReady():页面初次渲染完成时触发.一个页面只会调用一次,代表页面已 ...

  7. 2019年我的OKR(objectives and key results)目标与关键成果法

     一.学习目标目标1:每天必背诵英语单词(可可英语App,百词斩App),掌握英语的基本从句语法,听力训练必备(英语四六级听力题,主要是为通过四六级考试)目标2:考研准备,高数(大一上下册),现代(大 ...

  8. jq 点击复制div里面的内容 如果粘贴到富文本中,会将样式,里面所有的标签,文字一并粘贴进去

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  9. sqlserver 电脑重启以后服务突然无法启动 报错

    可能是sql server 评估期已过  在升级中输入产品密钥试试

  10. C语言面试题分类->排序算法

    1.选择排序. 每次将最小的数,与剩余数做比较.找到更小的,做交换. 时间复杂度:O(n²) 空间复杂度:O(1) 优缺点:耗时但内存空间使用小. void selectSort(int *p,int ...