SignalR有两种客户端和服务器端的数据交互模式:长连接模式和Hub(集线器模式)
1、SignalR的长连接模式
服务器端,新建一个继承PersistentConnection的自定义类(如果是vs2013,则编辑器新建项目里面会有创建“永久链接类”选项,这里我是用的vs2012,需要自定义个类)这个类的作用就是处理服务器接受客户端发送过来的消息以及将消息发送到客户端,如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
namespace MvcApplication2.SignalR
{
public class SignalRControll:PersistentConnection
{
protected override System.Threading.Tasks.Task OnConnected(IRequest request, string connectionId)
{
///当客户端连接到服务器的时候
return Connection.Send(connectionId, "欢迎");
}
protected override System.Threading.Tasks.Task OnReceived(IRequest request, string connectionId, string data)
{
///当服务器接收到客户端发送过来的消息的时候
//return Connection.Broadcast(data); //向所有在线客户端发送消息 1
return Connection.Send(connectionId, data);//向指定的客户端发送消息 2
}
protected override System.Threading.Tasks.Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
{
///当客户端和服务器断开连接的时候
return base.OnDisconnected(request, connectionId, stopCalled);
}
protected override System.Threading.Tasks.Task OnReconnected(IRequest request, string connectionId)
{
///当客户端和服务器重新连接的时候
return base.OnReconnected(request, connectionId);
}
}
}
完成了上面的消息处理代码之后怎样才能在系统中的后代跑起来上面的代码呢?用微软提供的Owin,新建一个包含Configuration(IAppBuilder app)的方法的自定义的类(如果是vs2013,则选择创建项的时候选择“OWIN Startup类“选项即可)
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(MvcApplication2.SignalR.HostStart))] //主要是在此处注册自定义的类
namespace MvcApplication2.SignalR
{
public class HostStart
{
public void Configuration(IAppBuilder app) //
{
app.MapSignalR<SignalRControll>("/myconnection"); //注册永久链接 1 客户端初始化永久链接的时候的参数要和此处一致,即“/myconnection”这个参数
app.MapSignalR(); //注册集线器 2
}
}
}
注意红色部分说明,如果只选用永久连接模式,则需要把下面的代码注释掉,反之亦然
客户端示例代码:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<script src="Scripts/jquery-1.7.1.min.js"></script>
<script src="Scripts/jquery.signalR-2.2.1.min.js"></script>
<script>
//获取当前时间
function getDate(){
var date=new Date();
return date.getFullYear()+"/"+date.getMonth()+"/"+date.getDate()+" "+date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
}
var conn = $.connection("/myconnection"); //初始化永久连接,注意此处的“/myconnection”参数需要和后台注册永久链接模式时的参数要保持一致
$(function () {
conn.start().done(function (data) { //当客户端连接上了服务器的时候执行的代码
$("#history").val(data.id);
});
conn.received(function (data) { //当客户端收到服务器传过来的信息的时候执行的代码
var history = $("#history").val();
history += "\n" + getDate() + "\n" + data;
$("#history").val(history);
});
});
function sendMSG() {
var content = $("#content").val();
if (content != "") {
conn.send(content); //向服务器发送消息
}
}
</script>
</head>
<body>
<p>
聊天记录:<br />
<textarea id="history"></textarea>
</p>
<p>
发送内容:<br />
<input type="text" id="content" /><br />
<input type="button" value="发送" οnclick="sendMSG()" />
</p>
</body>
</html>
执行结果截图如下:
如果将上面绿色代码处的代码1注释去掉的话,那么当在多个浏览器里面打开这个页面,然后再其中一个浏览器发送一条消息的时候,其他几个浏览器的页面也会显示这条消息
2、Hub(集线器模式)模式
后台代码部分,新建一个继承Hub类的自定义类,如下:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
namespace MvcApplication2.SignalR
{
public class MyHub:Hub
{
public void ServerHello()
{
///自定义方法,客户端可以“直接”访问的方法
}
public void ServerHello(string data,int index)
{
///自定义方法,客户端可以“直接”访问的方法
Debug.WriteLine("客户端调用服务器端方法");
Clients.All.clientHello(data,index); //调用客户端的方法clientHello,并且传递两个参数获取,注意客户端必须要定义一个包含两个参数,且名称为clientHello的函数
//上面Clients.All表示向所有在线客户端发送消息
}
public void ServerSend(string content, string connectionid)
{
///自定义方法客户端可以“直接”访问的方法
Clients.Client(connectionid).getServerContent(content); //调用客户端的方法getServerContent,并且传递一个参数过去,注意客户端必须要定义一个包含一个参数,且名称为getServerContent的函数
//Clients.Client(connectionid)表示向特定用户发送消息
}
public override System.Threading.Tasks.Task OnConnected()
{
///当客户端连接到服务器的时候
return Clients.Client(Context.ConnectionId).getConnectionID(Context.ConnectionId);
}
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
///当客户端和服务器断开连接的时候
return base.OnDisconnected(stopCalled);
}
public override System.Threading.Tasks.Task OnReconnected()
{
///当客户端和服务器重新连接的时候
return base.OnReconnected();
}
}
}
集线器模式的代码和永久链接模式的代码很相似,也是可以重写几个基类的方法,当时集线器模式里面没有接受信息的代码,而且可以自定义函数,这些自定义函数可以被客户端“直接“访问,同样完成了上面的代码也需要在后台注册,这样系统才能在后台将上面的代码跑起来,注册的方式已经在上面的代码里写过
客户端代码:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<script src="Scripts/jquery-1.7.1.min.js"></script>
<script src="Scripts/jquery.signalR-2.2.1.min.js"></script>
<script src="signalr/js"></script>
<script>
//手动代理
//var conn = $.hubConnection(); //初始化连接
//$(function () {
// var proxy= conn.createHubProxy("MyHub"); //获取服务代理
// proxy.on("clientHello", function (data,index) { //定义可供服务器调用的客户端方法clientHello,该方法包含两个参数
// console.log("服务器调用客户端代码");
// });
// conn.start().done(function (data) { //当客户端连接上服务器的时候执行的方法
// proxy.invoke("ServerHello"); //执行服务器端的方法ServerHello,此方法没有参数
// });
//});
//自动代理
var proxy = $.connection.myHub; //获取代理
var id; //客户端连接服务器时服务器动态分配的connectionoid
proxy.client.clientHello = function (data, index) { //定义可供服务器调用的客户端方法
console.log("服务器调用客户端代码");
}
proxy.client.getConnectionID = function (connectionid) { //定义可供服务器调用的客户端方法getConnectionID,该方法包含一个参数
$("#lblid").text(connectionid);
id=connectionid;
}
proxy.client.getServerContent = function (data) { //定义可供服务器调用的客户端方法getServerContent,该方法包含一个参数
$("#history").val(data);
}
$.connection.hub.start().done(function () { //当客户端连接上了服务器时候可以执行的代码
proxy.server.serverHello("调用服务器接口", 20); //调用服务器方法serverHello,服务器端必须定义一个serverHello方法,该方法包含两个参数
});
function sendSMG() {
var content = $("#content").val();
if (content != "") {
proxy.server.serverSend(content, id); //调用服务器端的方法send,服务器端必须定义一个Send的方法,该方法包含content和id两个参数
}
}
</script>
</head>
<body>
<label id="lblid"></label>
<p>
<textarea id="history"></textarea>
</p>
<p>
定向发送:<br />
<input type="text" id="content" /><br />
<input type="button" value="发送" οnclick="sendSMG()" />
</p>
</body>
</html>
注意上面紫色部分的js代码,因为集线器模式前端代码初始化链接的时候分为自动代理模式和手动代理模式,如果是手动代理模式,则只需要引用 <script src="Scripts/jquery-1.7.1.min.js"></script>, <script src="Scripts/jquery.signalR-2.2.1.min.js"></script>这两个脚本,如果是自动代理模式,服务器你会自动产生一个js脚本,如上面我引用了 <script src="signalr/js"></script>这个脚本,实际上这个脚本只是在执行的时候服务器自动给生成的,在编辑代码的时候是不存在这个脚本代码的,,
手动代理的时候,客户端在调用服务器端的函数的时候是没办法传参数的
执行结果截图如下:
在写这篇博客之前,我是看了一个大神的博客进行学习的,这是他的博客地址http://www.cnblogs.com/huangxincheng/p/5280630.html,我的这篇博客只是一篇学习记录,更详细的内容可以参考http://www.cnblogs.com/huangxincheng/p/5280630.html这篇博客