一步一步学习SignalR进行实时通信_2_Persistent Connections
标签(空格分隔): SignalR
前言
上一篇文章简单的介绍了下SignalR,从此篇文章就开始对SignalR进行剖析。在介绍Persistent connections之前,先简单介绍下安装signalR的方法。
我的开发环境:win10+vs2013
安装
- 首先我们新建一个空的MVC5的项目
- 通过Nuget[^Nuget]安装SignalR,通过
Tools->Nuget Package Manager->Package Manager Console
打开Package Manager Console
输入安装语句
Install-Package Microsoft.AspNet.SignalR
可以看到添加了JQuery和SignalR2.0
Persistent Connections
Persistent Connections的字面意思是持久连接,它有点类似于Sockets,在服务端和客户端都可以发送或接收数据。
映射并配置持久连接
如果我们要是实现基于
PersistentConnection
的实时信息传输,首先第一步我们需要在服务器启动时对_SignalR_进行配置。由于我们是基于_Owin_来实现_SignalR_的所以,我们在Startup
中找到Configuration
中配置,类似如果我们要实现其他的Owin
框架我们也可以在这里进行配置。
映射
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; using SignalR_2.Models; //设置Owin的启动项 [assembly: OwinStartup(typeof(SignalR_1.Startup))] namespace SignalR_· { public class Startup { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888 app.MapSignalR<EchoConnection>("/echo"); } } }
通过
MapSignalR()
方法来做映射,/echo
表示将会映射到/echo
,后面我我们转到MapSignalR定义
MapSignalR()
是一个扩展方法,它有许多重载方法,而我们主要关心的就是如图所示的泛型方法。这个方法的TConnection
要求是一个PersistentConnection
类型。好了,到此为止我们已经知道我们需要什么了,没必要继续深究下去。通过以上的研究,很明显,我们需要构造这么一个类去继承
PersistentConnection
来实现_SignalR_服务实现SignalR服务
我们新建一个类叫做EchoConnection
,代码如下:using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Web; using Microsoft.AspNet.SignalR;
namespace SignalR_1.Models
{
public class EchoConnection : PersistentConnection
{
/// <summary>
/// 当前连接数
/// </summary>
private static int _connections = 0;
/// <summary>
/// 连接建立时执行
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
protected override async Task OnConnected(IRequest request, string connectionId)
{
//原子操作,防止多条现成同时+1而只做一次变化
Interlocked.Increment(ref _connections);
await Connection.Send(connectionId, "Hi, " + connectionId + "!");
await Connection.Broadcast("新连接 " + connectionId + "开启. 当前连接数: " + _connections);
}
/// <summary>
/// 连接关闭时执行
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
protected override Task OnDisconnected(IRequest request, string connectionId)
{
//原子操作,防止多条现成同时-1而只做一次变化
Interlocked.Decrement(ref _connections);
return Connection.Broadcast(connectionId + " 连接关闭. 当前连接数: " + _connections);
}
/// <summary>
/// 连接开始时执行
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <param name="data"></param>
/// <returns></returns>
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
var message = connectionId + ">> " + data;
return Connection.Broadcast(message);
}
}
}我们定义了一个
EchoConnection
类继承PersistentConnetion
,并写了OnConnected
、OnDisconnected
、OnReceived
、三个方法,大致功能是当客户端连接时,服务器会通过Send()方法向它打招呼,参数是他的ConnectionId,并发送广播消息给所有客户端,并使总连接数+1,当客户端关闭连接时,服务器会广播给所有客户端XXX连接关闭,并使总连接数-1- 客户端实现
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>persistent connections</title>
<script src="Scripts/jquery-1.10.2.min.js"></script>
<script src="Scripts/jquery.signalR-2.0.0.min.js"></script>
</head>
<body>
<h1>Echo service</h1>
<div>
<input type="text" id="text" />
<button id="send">Send</button>
</div>
<script>
$(function () {
var connection = $.connection("/echo");
connection.logging = true;
connection.received(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
$(<span class="hljs-string">"body"</span>).append(data + <span class="hljs-string">"<br />"</span>);
});
connection.error(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
alert(<span class="hljs-string">"存在一个错误.
"</span> +
<span class="hljs-string">"Error: "</span> + err.message);
});
connection.start().done(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
$(<span class="hljs-string">"#send"</span>).click(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
connection.send($(<span class="hljs-string">"#text"</span>).val());
$(<span class="hljs-string">"#text"</span>).val(<span class="hljs-string">""</span>).focus();
});
});
});
</span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
</body>
</html>
对上面的代码有疑问看下面的图片
如图所示:左边是客户端的javascript代码,右边是服务器的代码
当客户端调用start方法时,会执行服务器的OnConnected方法
当客户端点击发送按钮发送消息时,服务端会在OnReceived中接收到消息
当服务端对消息进行发送或广播给客户端时,客户端receive会接收到此消息
结束语
这里通过PersistentConnection实现了在线聊天的简单例子。
注意在项目运行期间,我出现过几次程序集版本不对的情况,若出现此种情况,通过
Install-Package XXX
重装该程序集或Update-Package XXX
升级该程序集,一般均可解决
参考文献
SignalR Programming in Microsoft ASP.NET pdf 下载
[^Nuget]: NuGet 是免费、开源的包管理开发工具。
</div>