创建项目

创建一个空的 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. [BZOJ2707]走迷宫

    Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿 ...

  2. 活动页怎么切图photoshop

    一 切固定大小的单个图片 1.用pc打开图像 2.按ctrl+A(全选) 3.点击 选择 ->变换选区 ->拉参考线(把参考线放到最中央)->按回车 ->ctrl+d(取消全选 ...

  3. mysql主键约束和唯一性约束

    主键约束和唯一性约束都是索引,它们的区别是: 主键字段可以确保唯一性,但主键字段不能为NULL. 唯一性约束可以确保唯一性,但唯一性约束的字段可以为NULL 唯一性约束对含有NULL的记录不起作用,即 ...

  4. C#的命名管道(named pipe)

    命名管道是一种从一个进程到另一个进程用内核对象来进行信息传输.和一般的管道不同,命名管道可以被不同进程以不同的方式方法调用(可以跨权限.跨语言.跨平台).只要程序知道命名管道的名字,发送到命名管道里的 ...

  5. Android的UI调优

    对于一个App的UI而言,在流畅性上的改进目标其实就是降低屏幕绘制的延迟,创建流畅和稳定的帧率以避免卡顿. 在理想情况下,全部的测量.布局和绘制的时间最好在16ms以内,这样才能保证屏幕运行的顺畅性. ...

  6. Filter自动登录

    Dao层略过 Domain略过 Service层过 Web层 Select逻辑 获取表单数据,Web-service--Dao返回用户信息 如果返回不为null否则,重定向到登录页面.则判断用户是否勾 ...

  7. jquery的几个国内CDN加速节点

    分享几个jquery的几个国内国外的CDN加速节点,方便广大的开发设计者调用和节约空间,官网的总是最新版本的jquery所以不用去担心版本更新问题,其他加速节点可能不会在更新版本,所以取舍问题自己决定 ...

  8. 合并静态库出现 can't move temporary file错误

    静态库的制作就不说了很简单,网上也很多例子,这里主要讲下我合并通用静态库时候遇见的坑,在合并前注意.a文件一定要正确,我有一次scheme选了release但是device忘了换,结果怼着两个模拟器静 ...

  9. 数据库外连接及MySQL实现

    MySQL查询分为内连接查询和外连接查询,他们的区别在于:内连接查询的两个表示对等关系,根据条件进行匹配:外连接是以某一个表为主,两一个表根据条件进行关联.外连接分为左外连接.右外连接和全外连接.本文 ...

  10. [leetcode-582-Kill Process]

    Given n processes, each process has a unique PID (process id) and its PPID (parent process id). Each ...