天天看点

AspNet SignalR 解析简介 Demo 运行原理

简介

ASP.NET SignalR是ASP.Net的一个实时库,可以给页面加入实时功能,可以实时的将服务端的消息推送到页面中

ASP.NET SignalR都可以做什么?他主要完成服务端向客户端推送消息的操作,例如聊天室,广播,提醒等功能都能利用ASP.NET SignalR完成

可以参考官网:http://signalr.net/

Github: https://github.com/SignalR

接下来我们来分析一个Demo

Demo

BasicChat

工程结构如下:

图1

AspNet SignalR 解析简介 Demo 运行原理

首先我们先了解工程的引用情况,引用情况在packages.config文件中配置

packages.config 配置了所需的引用信息如下:

图2

AspNet SignalR 解析简介 Demo 运行原理

下载之后直接编译,IDE会根据packages.config直接去云服务中下载这些资源,请确保引用版本的一致,否则会出现运行失败的请况,因此各个包之间必须保持彼此对应

图3

AspNet SignalR 解析简介 Demo 运行原理

重新生成之后,会自动在引用中加入相应的DLL

图4

AspNet SignalR 解析简介 Demo 运行原理

生成成功,之后我们来看下运行效果

图5

AspNet SignalR 解析简介 Demo 运行原理

打开两个浏览器,一个IE11,一个是firefox

首先在IE里输入,消息会被服务器同时推到firefox

图6

AspNet SignalR 解析简介 Demo 运行原理

同样我们在Firefox浏览器里输入消息,同样会被服务器推送到IE客户端

图7

AspNet SignalR 解析简介 Demo 运行原理

看到效果之后,我们来熟悉一下工程结构

图8

AspNet SignalR 解析简介 Demo 运行原理

Demo 解析

以上的Demo我们需要关注三个文件

Index.html

         关键部分代码如下:

         <scriptsrc="Scripts/jquery-1.8.3.min.js"></script>

   <scriptsrc="Scripts/jquery.signalR-1.1.3.min.js"></script>

<scriptsrc="signalR/hubs"></script>

   <script>

       $(function () {

            var chat = $.connection.chat;

            chat.client.send =function (message) {

                $('#message').append('<li>' + message + '</li>');

            };

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

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

                    chat.server.send($('#msg').val());

                });

            });

       });

</script>

<scriptsrc="Scripts/jquery-1.8.3.min.js"></script>

   <scriptsrc="Scripts/jquery.signalR-1.1.3.min.js"></script>

<scriptsrc="signalR/hubs"></script>

         以上3行用来引用js脚本,其中<scriptsrc="signalR/hubs"></script>感觉很特殊,确实如此,他在这里起到了关键的作用,在后面的篇幅详细解释,这里我们先来看一下页面初始化做的操作

         <script>

       $(function () {

            var chat = $.connection.chat;

            chat.client.send =function (message) {

                $('#message').append('<li>' + message + '</li>');

            };

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

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

                    chat.server.send($('#msg').val());

                });

            });

       });

</script>

         这里我们会有疑问:

         1、$.connection.chat从何而来?

    2、chat.client是在什么地方定义?

    3、$.connection.hub.start().done(function () {})又做了什么操作?

         现在我们回到这里<scriptsrc="signalR/hubs"></script>我们看一下这里屏蔽了什么秘密?我们用Firefox和firbug查看一下资源请求:

图9

AspNet SignalR 解析简介 Demo 运行原理

         到这里我们大部分真相就了解了

         1、$.connection.chat是代理类,代理类分文两部分,一部分是服务端,一部分是客户端

2、客户端代理类有两个属性

   a) chat.client是客户端代理

   b) chat.server是服务端代理

   chat.client的方法可以提供给服务端调用,默认为空

   chat.server.send()方法是服务端 Chat类方法的代理,对应Chat类的Send方法

3、$.connection.hub.start().done(function () {})是jquery.signalR-1.1.3.min.js类库中提供的初始化入口

Chat.cs文件

publicclassChat :Hub

   {

       publicvoid Send(string message)

       {

            Clients.All.send(message+":[email protected]");

       }

}

Chat引用了Microsoft.AspNet.SignalR类库,继承了Hub类,当页面初始化操作时,就可以产生$.connection.chat js代理,客户端调用$.connection.chat.server.send(message);就能访问到服务端的代码

RegisterHubs.cs文件

程序入口文件

//声明程序的Start入口

[assembly:PreApplicationStartMethod(typeof(Samples.RegisterHubs),"Start")]

namespace Samples

{

   //静态类

   publicstaticclassRegisterHubs

{

    //静态方法

       publicstaticvoid Start()

       {

            var config =newHubConfiguration

            {

                EnableCrossDomain =true

            };

            RouteTable.Routes.MapHubs(config);

       }

   }

}

这样就完成了一个整个demo的分析

运行原理

SignalR 可以用于将任何种类的“实时”Web 功能添加到您的ASP.NET 应用程序。虽然我们经常把聊天应用作为最常用的一个例子,但实际上你可以利用它做很多事情。如果用户是通过刷新 web 页面,来查看新的数据,或者是通过页面实现长轮询来检索新的数据,那么就该考虑使用 SignalR 了。示例包括仪表板和监视应用程序、协作应用程序(例如同时编辑文档)、工作进度更新和实时表单等等。

SignalR 还适用于全新类型的 Web应用程序,特别是需要从服务器高频率更新的应用程序,例如实时游戏。一个好的例子,请参阅ShootR 游戏。

SignalR 提供一个简单的 API 用于创建服务器端到客户端的远程过程调用 (RPC),以便从服务器端 .NET 代码中调用客户端浏览器(以及其他客户端平台)中的 JavaScript 函数。SignalR 还包括用于管理连接(例如,连接和断开连接事件)和为连接分组的 API。

图10

AspNet SignalR 解析简介 Demo 运行原理

SignalR 会自动管理连接,并允许您像聊天室那样向所有连接的客户端同时发送消息。你也可以向特定的客户端发送消息。客户端和服务器之间的连接是持久性的,不像传统的 HTTP 连接 —— 每个通信都需要重新建立一个连接。

SignalR 支持“服务器推送”功能,即服务器代码可以使用远程过程调用 (PRC) 来调用浏览器中的客户端代码,而不使用目前在 Web 上常用的请求-响应模型。

SignalR 应用程序可以通过使用服务总线、SQL Server 或 Redis 扩展到数以千计的客户端.

SignalR 是开源的,可以通过GitHub 访问。

SignalR 和 WebSocket

SignalR 会在可能的情况下使用新的WebSocket 传输方式,并且在需要时回退到旧的传输方式。虽然您仍然可以直接使用 WebSocket 来编写应用程序,但是使用SignalR 意味着您有许多现成的额外功能可用,而无需自己实现这些功能。最重要的是,这意味着您可以使用 SignalR 编写应用程序以利用 WebSocket,而无需担心为旧的客户端单独创建代码。SignalR 还能够使你不必担心 WebSocket 的更新,因为 SignalR 会持续更新以支持基础传输方式的更改,为您的应用程序提供一致的接口以使用不同的 WebSocket 版本。

当然,您可以创建只使用 WebSocket 的解决方案,SignalR 为您提供了可能需要自行编写代码的所有功能,例如回退到其他的传输方式以及修订您的应用程序以更新到 WebSocket 实现。

传输和回退

SignalR 是对一组在构建客户端和服务器之间的real-time功能所需要使用的传输技术的抽象。SignalR 连接首先以 HTTP 发起请求,然后如果 WebSocket 可用的话,则升级到 WebSocket 连接。WebSocket 是 SignalR 的理想传输方式,因为它能够最高效地使用服务器的内存、有最低的延迟,而且有的最主要的功能(如客户端和服务器之间的全双工通信),但它也有最严格的环境需求: WebSocket 要求服务器是 Windows Server 2012 或 Windows 8 以及.NET Framework 4.5。如果不满足这些要求,SignalR 将尝试使用其他传输方式来建立连接。

HTML 5 传输

传输方式取决于是否支持 HTML 5。如果客户端浏览器不支持 HTML 5 标准,将使用较旧的传输方式。

WebSocket(如 果服务器和浏览器都指明它们支持Websocket)。WebSocket 是唯一一个在客户端和服务器之间建立真正的持久双向连接的传输方式。然而,WebSocket 也有最严格的要求;只有最新版本的 Microsoft Internet Explorer、Google Chrome 和 MozillaFirefox 完全支持,其他浏览器如 Opera 和 Safari 只有部分实现。

服务器发送事件,也称为 EventSource (如果浏览器支持服务器发送事件,基本上除了 Internet Explorer 之外其他的浏览器都支持此功能)。

Comet 传输

下列传输基于 Comet Web 应用程序模型,在该模型中有一个浏览器或其他客户端维护着一个长时间的 HTTP 请求,服务器可以在客户端没有明确请求的情况下使用此请求将数据推送到客户端。

ForeverFrame(仅限 Internet Explorer)。Forever Frame 会创建一个隐藏的 IFrame,对服务器上的终结点发送一个不完整的请求。然后服务器不断地发送脚本到客户端,并且立即执行这些脚本,从而建立一个从服务器到客户端的单向实时连接。从客户端到服务器的连接使用的是不同于服务器到客户端的连接,就像一个标准的 HTML 请求,对于每个需要发送的数据都会创建一个新连接。

Ajax的长轮询。长轮询不会创建一个持久性连接,而是通过一个请求来轮询服务器,使连接保持打开状态直到服务器发出响应,这时候再关闭该连接,然后立即请求一个新的连接。这可能会在连接重置时产生一些延迟。

有关各种配置所支持的传输方式的详细信息,请参见支持的平台.

传输方式选择过程

下面的列表显示 SignalR 决定使用的传输方式的步骤。

1.  如果浏览器是Internet Explorer 8 或更早版本,则使用长轮询。

2.  如果配置了JSONP (即连接启动时

jsonp

参数设置为

true

),则使用长轮询。

3.  如果正在使用跨域的连接 (即 SignalR 终结点和宿主页不在相同的域中),并且符合以下的条件将使用WebSocket :

o    客户端支持 CORS(Cross-Origin Resource Sharing)。哪种客户端支持 CORS 的详细信息,请参阅在 caniuse.com CORS.

o    客户端支持WebSocket

o    服务器支持WebSocket

如果这些标准中的任何一条不满足,将使用长轮询。跨域连接的详细信息,请参阅如何建立跨域的连接.

4.  如果不配置为使用JSONP 、连接不跨域并且客户端和服务器都支持,将使用 WebSocket 。

5.  如果客户端或服务器不支持 WebSocket,则尽量使用服务器发送事件。

6.  如果服务器发送事件不可用,则将尝试使用 Forever Frame。

7. 如果 Forever Frame 不可用,则使用长轮询。

Monitoring 传输方式

您可以通过在您的应用程序hub启用日志记录,并在您的浏览器的控制台窗口中查看您的应用程序使用哪种传输协议。

将下面的命令添加到您的客户端应用程序,以在浏览器中启用hub事件的日志记录:

$.connection.myHub.logging= true;

·        在IE中,通过按 f12 键,可以打开开发人员工具,然后单击控制台选项卡。

图11

AspNet SignalR 解析简介 Demo 运行原理

在 Chrome,按下 Ctrl + Shift + J 打开控制台。

图12

AspNet SignalR 解析简介 Demo 运行原理

通过控制台的日志记录,你就能够看到 SignalR 正在使用的传输协议。

图13

AspNet SignalR 解析简介 Demo 运行原理

指定传输协议

使用固定的传输协议需要一定的时间和客户端以及服务器的资源。如果客户端环境已知,那么当启动客户端连接时就可以指定传输协议。下面的代码段演示如何在已知客户端不支持任何其他协议时,直接在连接开始时就使用 Ajax 的长轮询:

connection.start({ transport: 'longPolling' });

如果你想要一个客户端按照特定顺序尝试传输方式,您可以指定尝试的顺序。下面的代码段演示如何尝试使用 WebSocket 并且在失败的时间去直接使用长轮询。

connection.start({ transport:['webSockets','longPolling'] });

用于指定传输方式的字符串常量的定义如下:

  • webSockets
  • forverFrame
  • serverSentEvents
  • longPolling

连接和Hubs

SignalR API 包含两种客户端和服务器之间进行通信的模型: 永久连接和Hubs。

连接表示为一个发送单 个、 编组或广播消息的简单终结点。开发人员可以使用持久性连接 API(在.NET 代码中由 PersistentConnection 类表示)直接访问 SignalR 公开的底层通信协议的 。使用过基于连接 Api 比如wcf的开发人员会更加熟悉连接通信模型。

Hub 是基于连接 API的但是更高级别的通信管线,它允许客户端和服务器上彼此直接调用方法。SignalR 能够很神奇地处理跨机器的调度,使得客户端能够调用在服务器上的方法就像轻松地调用本地方法,反之亦然。使用过基于远程调用的 Api比如 .NET Remoting的开发人员会更加熟悉 Hubs通信模型。使用Hub还允许您将强类型的参数传递给方法并且绑定模型。

体系结构关系图

下面的关系图显示了Hub、 持续连接和用于传输的基础技术之间的关系。

图14

AspNet SignalR 解析简介 Demo 运行原理
Hub的工作原理

当 服务器端代码调用客户端上的方法时,服务器发送一个数据包其中包含的要调用的方法的名称与参数(当被发送的方法参数包含对象时,它将被序列化为JSON)。然后,客户端通过方法的名称在客户端代码中定义的方法中尝试匹配。如果匹配成功,则将执行客户端方法并且使用经过反序列化的参数数据。

可以使用Fiddler之类的工具监视方法的调用。下图显示了Fiddler的日志窗格中从 SignalR 的服务器发送到 web 浏览器客户端的方法调用。从Hub发起调用的方法称为

MoveShapeHub

,被调用的方法是

updateShape

.

图15

AspNet SignalR 解析简介 Demo 运行原理

在此示例中,集线器名称使用参数

H

标识;方法名称使用参数

M

标识,同时正在发送给该方法的数据使用参数

A

标识。生成此消息的应用程序是在High-Frequency Realtime教程中创建的。

选择通信模型

大多数应用程序应使用Hub的 API。连接 API 可用于以下情况:

  • 发送的实际消息需要指定的格式。
  • 开发人员更喜欢使用消息传递和调度模型,而不是一个远程调用模型。
  • 使用 SignalR移植的现有的应用程序正在使用消息传递模型。