创建项目

创建一个空的 Web 项目,并在 Nuget 里面添加 SignalR,jQuery UI 包,添加以后项目里包含了 jQuery,jQuery.UI ,和 SignalR 的脚本。

创建基础应用

添加一个 SignalR Hub 类,并命名为 MoveShapeHub ,更新代码。

using Microsoft.AspNet.SignalR;
using Newtonsoft.Json; namespace SignalRDemo3
{
public class MoveShapeHub : Hub
{
public void UpdateModel(ShapeModel clientModel)
{
clientModel.LastUpdatedBy = Context.ConnectionId;
// Update the shape model within our broadcaster
Clients.AllExcept(clientModel.LastUpdatedBy).updateShape(clientModel);
}
} public class ShapeModel
{
// We declare Left and Top as lowercase with
// JsonProperty to sync the client and server models
[JsonProperty("left")]
public double Left { get; set; }
[JsonProperty("top")]
public double Top { get; set; }
// We don't want the client to get the "LastUpdatedBy" property
[JsonIgnore]
public string LastUpdatedBy { get; set; }
}
}

当程序启动的时候启动Hub

添加 Owin 类,并在里面配置 SignalR

using Microsoft.Owin;
using Owin; [assembly: OwinStartup(typeof(SignalRDemo3.Startup))] namespace SignalRDemo3
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
app.MapSignalR();
}
}
}

添加客户端

添加一个名为 Index 的 html 页面,并设置为启动页面。

<!DOCTYPE html>
<html>
<head>
<title>SignalR MoveShape Demo</title>
<style>
#shape {
width: 100px;
height: 100px;
background-color: #FF0000;
}
</style>
</head>
<body>
<script src="Scripts/jquery-3.1.1.min.js"></script>
<script src="Scripts/jquery-ui-1.12.1.min.js"></script>
<script src="Scripts/jquery.signalR-2.2.2.js"></script>
<script src="/signalr/hubs"></script>
<script>
$(function () {
var moveShapeHub = $.connection.moveShapeHub,
$shape = $("#shape"),
shapeModel = {
left: 0,
top: 0
};
moveShapeHub.client.updateShape = function (model) {
shapeModel = model;
$shape.css({ left: model.left, top: model.top });
};
$.connection.hub.start().done(function () {
$shape.draggable({
drag: function () {
shapeModel = $shape.offset();
moveShapeHub.server.updateModel(shapeModel);
}
});
});
});
</script> <div id="shape" />
</body>
</html>

上面的 Html 和 JavaScript 代码创建一个名为 Shape 的 Div ,并且通过jQuery库给 Shape 提供了拖拽功能,并通过拖拽事件向服务器发送 Shape 的当前位置。

现在可以 F5 启动调试看效果,当程序启动以后,打开另一个浏览器窗口,输入地址,你可以在一个窗口拖拽红色的 Shape,另一个窗口的 Shape 也会跟着动。

添加客户端循环

如果每次鼠标移动都发送数据到服务端,那就需要很多网络流量,我们必须降低发送数据的频率。我们可以通过 setInterval 函数,设置一个固定的时间来发送数据到服务器。

<!DOCTYPE html>
<html>
<head>
<title>SignalR MoveShape Demo</title>
<style>
#shape {
width: 100px;
height: 100px;
background-color: #FF0000;
}
</style>
</head>
<body>
<script src="Scripts/jquery-3.1.1.min.js"></script>
<script src="Scripts/jquery-ui-1.12.1.min.js"></script>
<script src="Scripts/jquery.signalR-2.2.2.js"></script>
<script src="/signalr/hubs"></script>
<script>
$(function () {
var moveShapeHub = $.connection.moveShapeHub,
$shape = $("#shape"),
// Send a maximum of 2 messages per second
// (mouse movements trigger a lot of messages)
messageFrequency = 2,
// Determine how often to send messages in
// time to abide by the messageFrequency
updateRate = 1000 / messageFrequency,
shapeModel = {
left: 0,
top: 0
},
moved = false;
moveShapeHub.client.updateShape = function (model) {
shapeModel = model;
$shape.css({ left: model.left, top: model.top });
};
$.connection.hub.start().done(function () {
$shape.draggable({
drag: function () {
shapeModel = $shape.offset();
moved = true;
}
});
// Start the client side server update interval
setInterval(updateServerModel, updateRate);
});
function updateServerModel() {
// Only update server if we have a new movement
if (moved) {
moveShapeHub.server.updateModel(shapeModel);
moved = false;
}
}
});
</script> <div id="shape" />
</body>
</html>

可以用上面的代码更新刚才的 Index.html页面,然后F5调试,可以发现现在拖动一个 Shape 以后在另一个浏览器里的 Shape 半秒钟才会更新。

增加服务端循环

更新 MoveShapeHub.cs

using Microsoft.AspNet.SignalR;
using Newtonsoft.Json;
using System;
using System.Threading; namespace SignalRDemo3
{
public class Broadcaster
{
private readonly static Lazy<Broadcaster> _instance =
new Lazy<Broadcaster>(() => new Broadcaster());
// We're going to broadcast to all clients once 2 second
private readonly TimeSpan BroadcastInterval =
TimeSpan.FromMilliseconds();
private readonly IHubContext _hubContext;
private Timer _broadcastLoop;
private ShapeModel _model;
private bool _modelUpdated;
public Broadcaster()
{
// Save our hub context so we can easily use it
// to send to its connected clients
_hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>();
_model = new ShapeModel();
_modelUpdated = false;
// Start the broadcast loop
_broadcastLoop = new Timer(
BroadcastShape,
null,
BroadcastInterval,
BroadcastInterval);
}
public void BroadcastShape(object state)
{
// No need to send anything if our model hasn't changed
if (_modelUpdated)
{
// This is how we can access the Clients property
// in a static hub method or outside of the hub entirely
_hubContext.Clients.AllExcept(_model.LastUpdatedBy).updateShape(_model);
_modelUpdated = false;
}
}
public void UpdateShape(ShapeModel clientModel)
{
_model = clientModel;
_modelUpdated = true;
}
public static Broadcaster Instance
{
get
{
return _instance.Value;
}
}
} public class MoveShapeHub : Hub
{
// Is set via the constructor on each creation
private Broadcaster _broadcaster;
public MoveShapeHub()
: this(Broadcaster.Instance)
{
}
public MoveShapeHub(Broadcaster broadcaster)
{
_broadcaster = broadcaster;
}
public void UpdateModel(ShapeModel clientModel)
{
clientModel.LastUpdatedBy = Context.ConnectionId;
// Update the shape model within our broadcaster
_broadcaster.UpdateShape(clientModel);
}
} public class ShapeModel
{
// We declare Left and Top as lowercase with
// JsonProperty to sync the client and server models
[JsonProperty("left")]
public double Left { get; set; }
[JsonProperty("top")]
public double Top { get; set; }
// We don't want the client to get the "LastUpdatedBy" property
[JsonIgnore]
public string LastUpdatedBy { get; set; }
}
}

上面的代码新建了一个 Broadcaster 类,通过类 Timer 来进行节流。

因为 Hub 实例每次都会重新创建,所以只能创建一个 Broadcaster 的单例模型。调用客户端 UpdateShape 的方法被移出了 hub 。现在它通过类 Broadcaster 来管理,通过名为 _broadcastLoop 的 timer 每两秒更新一次。

最后因为不能直接在 hub 里调用客户端方法,类 Broadcaster 需要通过 GlobalHost 来获取到当前进行操作的 hub。

最终使用 F5 进行调试,虽然客户端设置了半秒一次的刷新,但是因为服务器端设置了2秒一次刷新,所以你在当前浏览器里移动 Shape ,两秒钟过后另一个浏览器里的 Shape 才会移动到当前位置。

源代码链接:

链接: https://pan.baidu.com/s/1o8NXwTW 密码: 5r5i

参考链接:

https://docs.microsoft.com/zh-cn/aspnet/signalr/overview/getting-started/tutorial-high-frequency-realtime-with-signalr

【SignalR学习系列】3. SignalR实时高刷新率程序的更多相关文章

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

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

  2. 【SignalR学习系列】1. SignalR理论介绍

    什么是SignalR? ASP.NET SignalR 是一个让 ASP.NET开发者可以简单地给自己的程序添加即时通讯功能的开发库.即时通讯功能可以直接从服务器端给在线的客户端发送数据,而不用等待客 ...

  3. 【SignalR学习系列】4. SignalR广播程序

    创建项目 创建一个空的 Web 项目,并在 Nuget 里面添加 SignalR,jQuery UI 包,添加以后项目里包含了 jQuery,jQuery.UI ,和 SignalR 的脚本. 服务端 ...

  4. 【SignalR学习系列】8. SignalR Hubs Api 详解(.Net C# 客户端)

    建立一个 SignalR 连接 var hubConnection = new HubConnection("http://www.contoso.com/"); IHubProx ...

  5. 【SignalR学习系列】7. SignalR Hubs Api 详解(JavaScript 客户端)

    SignalR 的 generated proxy 服务端 public class ContosoChatHub : Hub { public void NewContosoChatMessage( ...

  6. 【SignalR学习系列】6. SignalR Hubs Api 详解(C# Server 端)

    如何注册 SignalR 中间件 为了让客户端能够连接到 Hub ,当程序启动的时候你需要调用 MapSignalR 方法. 下面代码显示了如何在 OWIN startup 类里面定义 SignalR ...

  7. 【SignalR学习系列】5. SignalR WPF程序

    首先创建 WPF Server 端,新建一个 WPF 项目 安装 Nuget 包 替换 MainWindows 的Xaml代码 <Window x:Class="WPFServer.M ...

  8. 【SignalR学习系列】2. 第一个SignalR程序

    新建项目 1.使用VisualStudio 2015 新建一个Web项目 2.选择空模板 3.添加一个新的SignalR Hub Class (v2)类文件,并修改类名为ChatHub 4.修改Cha ...

  9. SpringCloud学习系列之一 ----- 搭建一个高可用的注册中心(Eureka)

    前言 本篇主要介绍的是SpringCloud相关知识.微服务架构以及搭建一个高可用的服务注册与发现的服务模块(Eureka). SpringCloud介绍 Spring Cloud是在Spring B ...

随机推荐

  1. 安装Mysql5.7并修改初始密码

    Centos 安装MySQL可以参考之前写的一篇文章 Centos7.3 安装Mysql5.7并修改初始密码 windows安装mysql5.7有两种方式 1.下载.msi安装文件直接根据界面提示进行 ...

  2. JDK并发包

    JDK5之后引进了并发包java.util.concurrent,让并发的开发更加可控,更加简单.所以有必要好好学习下,下面从同步控制.并发容器.线程池三部分来详细了解它. 1. 各种同步控制工具的使 ...

  3. php简单的文件操作

    (1)先要想好要操作哪个文件? (2)确定文件的路径? (3)要有什么文件管理功能? 一.先做一下简单的查看文件功能,文件中的文件和文件夹都显示,但是双击文件夹可以显示下一级子目录,双击"返 ...

  4. 为网页生成二维码(jquery.qrcode.min.js)

    做网站活动页面的时候,要为每个活动生成一个二维码,虽然简单,但还是习惯记录下来. jquery.qrcode.min.js是js的一个库,主流的浏览器都支持:IE6~10, Chrome, Firef ...

  5. C++判断一个数字是否为质数

    关于素数的算法是程序竞赛比较重要的数论知识,我们来看通常会使用的几个算法. 我们先来复习几个基本概念: 质数:对于大于1的自然数,若除了1和它本身,没有别的因数,则称这个数为质数,质数也叫素数.反之, ...

  6. angular js 和 dajango 标签{{}} 冲突

    问题描述: 如果在django的模板中使用{{ }},不会被angularjs 识别. 解决办法: >1.5 的django中,将需要angularjs解释的{{expression}}放在 v ...

  7. 映射语句之INSERT语句

    1.一个 INSERT SQL 语句可以在<insert>元素在映射器 XML 配置文件中配置 例子: <insert id="insertStudentWithId&qu ...

  8. IE11中navigator.userAgent的变化

    在原来判断浏览器是否是ie时,我们可以根据navigator.userAgent中时候有MSIE,但是IE11进行变革,userAgent中不在包含MSIE字段, 在实际项目中,入到类似的在控制台报错 ...

  9. Java 9 揭秘(6. 封装模块)

    Tips 做一个终身学习的人. 在这章节中, 主要介绍以下内容: 封装Java模块的不同格式 JAR格式增强 什么是多版本JAR 如何创建和使用多版本JAR JMOD是什么格式 如何使用jmod工具来 ...

  10. 【LeetCode】87. Scramble String

    题目: Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty subs ...