ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信。什么是实时通信的Web呢?就是让客户端(Web页面)和服务器端可以互相通知消息及调用方法,当然这是实时操作的。
WebSockets是HTML5提供的新的API,可以在Web网页与服务器端间建立Socket连接,当WebSockets可用时(即浏览器支持Html5)SignalR使用WebSockets,当不支持时SignalR将使用其它技术来保证达到相同效果。
SignalR当然也提供了非常简单易用的高阶API,使服务器端可以单个或批量调用客户端上的JavaScript函数,并且非常 方便地进行连接管理,例如客户端连接到服务器端,或断开连接,客户端分组,以及客户端授权,使用SignalR都非常 容易实现。
SignalR 将与客户端进行实时通信带给了ASP .NET 。当然这样既好用,而且也有足够的扩展性。以前用户需要刷新页面或使用Ajax轮询才能实现的实时显示数据,现在只要使用SignalR,就可以简单实现了。
最重要的是您无需重新建立项目,使用现有ASP .NET项目即可无缝使用SignalR。
最近因为项目中涉及到了实时数据的传输,特地去了解了一下当前Web应用中常见的实时交互手段,当然一开始也不仅限于Web客户端。从c#自带的Socket类,到Html5中的WebSocket,再到Asp .Net利器SignalR,总算将这块知识点及应用入门了,当然今天的主要内容还是Web端的消息交互技术(Ajax,Comet,WebSocket等),这些技术难度有中有低,应用场所也有不同,最后我们要根据项目情况来选择恰当的技术。接下来便简单介绍一下
Web消息交互技术
常见技术
应用技术 | 说明 | 优缺点 |
---|---|---|
轮询(polling) | 这应该是最常见的一种实现数据交互的方式,开发人员控制客户端以一定时间间隔中向服务器发送Ajax查询请求大,但是也因此,当服务器端内容并没有显著变化时,这种连接方式将带来很多无效的请求,造成服务器资源损耗。适合并发量小,实时性要求低的应用模型,更像是定时任务。 | 优点:实现最为简单,配置简单,出错几率小 缺点:每次都是一次完整的http请求,易延迟,有效请求命中率少,并发较大时,服务器资源损耗大 |
长轮询(long polling) | 长轮询是对轮询的改进,客户端通过请求连接到服务器,并保持一段时间的连接状态,直到消息更新或超时才返回Response并中止连接,可以有效减少无效请求的次数。属于Comet实现 | 优点:有效减少无效连接,实时性较高 缺点:客户端和服务器端保持连接造成资源浪费,服务器端信息更新频繁时,long polling并不比polling高效,并且当数据量很大时,会造成连续的polls不断产生,性能上反而更糟糕 |
iframe流 | iframe流方式是在页面中插入一个隐藏的iframe,利用其src属性在服务器和客户端之间创建一条长链接,服务器向iframe传输数据(通常是HTML,内有负责插入信息的javascript),来实时更新页面。属于Comet实现 | 优点:实时性高,浏览器兼容度好 缺点:客户端和服务器端保持长连接造成资源浪费 |
WebSocket | WebSocket是HTML5提供的一种在单个 TCP 连接上进行全双工通讯的协议,目前chrome、Firefox、Opera、Safari等主流版本均支持,Internet Explorer从10开始支持。另外因为WebSocket 提供浏览器一个原生的 socket实现,所以直接解決了 Comet 架构很容易出错的问题,而在整個架构的复杂度上也比传统的实现简单得多。 | 优点:服务器与客户端之间交换的数据包档头很小,节约带宽。全双工通信,服务器可以主动传送数据给客户端。 缺点:旧版浏览器不支持 |
Comet 简介
浏览器作为 Web 应用的前台,自身的处理功能比较有限。浏览器的发展需要客户端升级软件,同时由于客户端浏览器软件的多样性,在某种意义上,也影响了浏览器新技术的推广。在 Web 应用中,浏览器的主要工作是发送请求、解析服务器返回的信息以不同的风格显示。AJAX 是浏览器技术发展的成果,通过在浏览器端发送异步请求,提高了单用户操作的响应性。但 Web 本质上是一个多用户的系统,对任何用户来说,可以认为服务器是另外一个用户。现有 AJAX 技术的发展并不能解决在一个多用户的 Web 应用中,将更新的信息实时传送给客户端,从而用户可能在“过时”的信息下进行操作。而 AJAX 的应用又使后台数据更新更加频繁成为可能。
WebSocket介绍
WebSocket本质上是一个基于TCP的持久化协议,相对于HTTP这种非持久的协议来说,它能够更好的节省服务器资源和带宽,并且真正实现实时通信。以下是它与传统技术的性能对比图(Websocket.org提供)
我们可以看到相比于传统技术,在流量和负载逐渐增大时,WebSocket的性能表现是远远超过它们的。
SignalR是什么
SignalR是一个.Net开源库,用于构建需要实时进行用户交互和数据更新的Web应用,如在线聊天,游戏,天气或者股票信息更新等实时应用程序。SignalR简化了构建实时应用的过程,它包括了一个Asp .Net服务器端库和一个Js端库,集成了数种常见的消息传输方式,如long polling
,WebSocket
,并提供相应的Api供开发人员选择如何调用,帮助其可以简单快速地实现客户端与服务器端相互间的实时通信。当环境条件合适时,SignalR将WebSocket作为底层传输方式的优先实现,当然,它也能很高效地回退到其他技术。同时,SignalR提供了非常良好的Api以供远程调用(RPC) 浏览器中的js代码。接下来,看看SignalR的传输方式和通信模型,这是SignalR的核心所在。
SignalR基本适用于任何可以用上述技术实现的场合,但是对寄宿平台版本有要求。如.Net Framework 平台,SignalR库需要4.5及以上版本的支持,而Mono上也实现了SignalR。如果是最新的.Net Core 1.0,建议大家直接使用SelfHost方式寄宿。
默认传输方式
传输方式 | 选择条件 |
---|---|
long polling | 1.IE8或更早版本 2.连接启动时JSONP参数设置为TRUE 3.Forever Frame不可用 |
WebSocket | 1.正在使用跨域连接,并且符合以下条件(以下不满足任一条则使用长轮询) (1).客户端支持CORS (2).客户端支持WebSocket (3).服务器端支持WebSocket 2.不配置使用JSONP,连接不跨域并且客户端和服务器端都支持WebSocket (1).客户端支持CORS (2).客户端支持WebSocket (3).服务器端支持WebSocket |
ServerSendEvent | 客户端或服务器端不支持Websocket |
Forever Frame | EventSource不可用(基本上除了IE外都支持) |
自动管理传输方式
不指定传输方式时,SignalR会以Http方式发起请求,比对客户端和服务器端后,假如WebSocket可用,则自动升级到WebSocket模式,WebSocket是最理想的传输方式,除了能高效使用服务器内存,低延迟,还能实现客户端和服务器端的全双工通信。开发人员可以通过SignalR中js库的$.connection.chatHub.logging = true;
来启用hub事件的日志记录
通信模型
SignalR包括两种客户端和服务器端之间进行通信的模型,Persistent Connections
和Hubs
。
通信模型 | 说明 |
---|---|
Persistent Connections | Persistent Connections表示一个发送单个,编组,广播信息的简单终结点。开发人员通过使用持久性连接Api,直接访问SignalR公开的底层通信协议。 |
Hubs | Hubs是基于连接Api的更高级别的通信管道,它允许客户端和服务器上彼此直接调用方法,SignalR能够很神奇地处理跨机器的调度,使得客户端和服务器端能够轻松调用在对方端上的方法。使用Hub还允许开发人员将强类型的参数传递给方法并且绑定模型 |
SignalR具体开发步骤
Hubs的示例网上已经很多了(文章末尾附上链接),这边先来快速开始一个SignalR使用永久连接的Demo.
关于永久连接和Hubs的区别,这里有些很棒的解释.
(1)安装Nuget包
创建一个默认的Asp .Net Mvc项目使用Install-Package Microsoft.AspNet.SignalR
安装SignalR包
(2)增加SignalR服务
新增Connections
文件夹,添加SignalR永久连接类ChatConnections
using System.Threading.Tasks;using Microsoft.AspNet.SignalR;namespace SignalRUsingPersistentConnectionsDemo.Connections{ public class ChatConnection : PersistentConnection
{ protected override Task OnConnected(IRequest request, string connectionId) { return Connection.Send(connectionId, "Welcome!");
} protected override Task OnReceived(IRequest request, string connectionId, string data) { return Connection.Broadcast(data);
}
}
}
(3)增加Startup启动类
代码语言:javascript复制using Microsoft.Owin;using Owin;using SignalRUsingPersistentConnectionsDemo;using SignalRUsingPersistentConnectionsDemo.Connections;
[assembly: OwinStartup(typeof (Startup))]namespace SignalRUsingPersistentConnectionsDemo{ public class Startup
{ public void Configuration(IAppBuilder app) { // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888
// 配置上文实现的ChatConnections
app.MapSignalR<ChatConnection>("/Connections/ChatConnection");
}
}
}
(4)前端js配置
前端js实现消息广播,并实时记录
代码语言:javascript复制@{
Layout = null;
}<script src="~/Scripts/jquery-1.10.2.min.js"></script><script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script><script type="text/javascript">
$(function () { var connection = $.connection("/Connections/ChatConnection");
$('#displayname').val(prompt('Enter your name:', ''));
$("msg").focus();
connection.received(function (data) {
$('#messages').append('<li>' data '</li>');
});
connection.start().done(function() {
$("#broadcast").click(function () {
connection.send($('#displayname').val() ':' $('#msg').val());
});
});
});</script><input type="text" id="msg" /><input type="button" id="broadcast" value="broadcast"/><input type="hidden" id="displayname" /><ul id="messages"></ul>
(5)实际效果
(6).Net Client实现
除了Web实时应用之外,你也可以用其他应用程序实现实时交互,如控制台。只需要Install-Package Microsoft.AspNet.SignalR.Client
命令,示例编码如下
using Microsoft.AspNet.SignalR.Client;using static System.Console;namespace DotnetClientWithSignalRDemo{ internal class Program
{ private static void Main(string[] args) { var connection = new Connection("http://localhost:1508/Connections/ChatConnection");
connection.Received = WriteLine;
connection.Start().Wait(); string line; while ((line = ReadLine()) != null)
{
connection.Send(line).Wait();
}
}
}
}
效果如图,同样实现了双向通信
简单示例教程入门版
SignalR的简单教程制作一个在线的聊天
- 前端用了国产的一个MVVM框架 avalon 的早期版本和 layer 插件
- MVC项目里面新增一个Hub 的继承类 ChatHub , 标签HubName 类似于一个重命名的效果
- OnlineCache 类的作用是定义了一个KEY和VALUE主要用于记录用户名称和Signalr自动生成的KEY关系
- Startup.cs 里记得注册下 app.MapSignalR();