教程简介

SignalR的好处是可以让多个客户端之间进行互动,比如这篇教程就展示了当你在页面上拖动矩形方块的同时,其它打开这个页面的用户也将会看到你拖动的轨迹以及最终的结果,当然他们也可以通过拖动该方块来改变你的网页上该方块的位置。如果对其进行扩展一下,说不定还能搞出来一个供多人完成的涂鸦墙。该教程出自High-Frequency Realtime with SignalR 2,有兴趣的可以看原教程。

创建项目

1.打开Visual Studio,并创建一个新的ASP.NET Web Application项目,选择Empty模板,然后点击OK,创建项目。

2.依次单击Tools | NuGet Package Manager | Package Manager Console,打开NuGet控制台。

3.输入命令Install-Package Microsoft.AspNet.SignalR安装SignalR组件。

4.输入命令Install-Package jQuery.UI.Combined安装jQuery UI,并升级jQuery文件。

5.打开Solution Explorer可以看到对应的jQueryjQueryUISignalR,如下图所示。

添加Hub

1.右击项目文件,依次点击Add | New Item | Web | SignalR | SignalR Hub Class(v2),然后创建一个名为MoveShapeHub.cs的Hub文件。

2.在MoveShapeHub类中输入下面这段代码。

using Newtonsoft.Json;
using Microsoft.AspNet.SignalR; namespace MoveShapeDemo
{
public class MoveShapeHub : Hub
{
public void UpdateModel(ShapeModel clientModel)
{
clientModel.LastUpdateBy = Context.ConnectionId; // Clients.Others.updateShape(clientModel);
Clients.AllExcept(clientModel.LastUpdateBy).updateShape(clientModel);
}
} public class ShapeModel
{
/// <summary>
/// 使用JsonProperty指定的名称来序列化该属性
/// </summary>
[JsonProperty("left")]
public double Left { get; set; } /// <summary>
/// 同上
/// </summary>
[JsonProperty("top")]
public double Top { get; set; } /// <summary>
/// 使用JsonIgnore表示序列化时忽略该属性
/// </summary>
[JsonIgnore]
public string LastUpdateBy { get; set; }
}
}

添加Hub的启动文件

1.使用SignalR必需要添加启动文件(而这个启动文件则是基于OWIN的),在Solution Explorer里,右键项目,然后依次点击Add | New Item | Web | General | OWIN Startup Class,创建一个名为Startup.cs的启动文件。

2.在Startup类中输入下面这段代码。

using Microsoft.Owin;
using Owin; [assembly: OwinStartup(typeof(MoveShapeDemo.Startup))] namespace MoveShapeDemo
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}

添加客户端文件

1.服务端的工作完成后,再来编写客户端的代码,右键项目,并在根目录新建一个名为index.html的网页文件。

2.将下面这段代码拷备到新建的网页文件中。

<!DOCTYPE html>
<html>
<head>
<title>SignalR MoveShape Demo</title>
<style>
#shape {
width: 100px;
height: 100px;
background-color: #FF0000;
}
</style>
<script src="Scripts/jquery-1.12.4.js"></script>
<script src="Scripts/jquery-ui-1.12.1.js"></script>
<script src="Scripts/jquery.signalR-2.2.1.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>
</head>
<body>
<div id="shape" />
</body>
</html>

3.准备注绪后,按F5,并使用多个浏览器打开,试着在任何一个浏览器页面上拖动这个方块,就可以看到不管你在哪一个浏览器页面托动这个方块,所有打开的页面上这个方块都会跟着移动。不过这个测试案例并不是很好,因为只要你移动方块,它就会与服务器进行交互,这样就会造成网络带宽不必要的浪费,所以要改进一下。

改进一:客户端定时发送移动的新坐标

为了不使客户端移动的每一像素都发送给服务器,我们决定采用setInterval函数来让客户端定时把最新的坐标信息发送给服务器,并且加上一个开关,只有在移动后才会发送最新的坐标数据。

将静态页的代码改为下面这个样子(只给出脚本部分)

<script>
var moveShapeHub,
shapeModel,
moved; $(function () {
moveShapeHub = $.connection.moveShapeHub;
moved = false;
shapeModel = {
left: 0,
top: 0
}; var $shape = $("#shape"),
messageFrequency = 10, // 限定每秒最多发送10个消息
updateRate = 1000 / messageFrequency; // 设置每个消息发送的间隔时间 // 声明的回调方法
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;
}
}); // 使用定时器定时向服务器发送新坐标
setInterval(updateServerModel, updateRate);
});
}); function updateServerModel() {
if (moved) {
moveShapeHub.server.updateModel(shapeModel);
moved = false;
}
}
</script>

重新运行程序,再次拖动矩形时,客户端就会以每秒最多10次的频率来与服务器传递数据,虽然节省了带宽,不过其它客户端的矩形在被移动时就会像PPT一样,没有那么顺滑了,不过这都不叫事儿。

改进二:服务器定时将数据广播给其它客户端

在这个例子中,服务器端只要一接收到数据就将它广播给其它的客户端,而这就会存在与上面客户端类似的问题,所以我们这次也要对服务器端的代码进行改造,让它定时向客户端广播数据。

MoveShapeHub.cs里的代码改为下面的代码。

using Microsoft.AspNet.SignalR;
using Newtonsoft.Json;
using System;
using System.Threading; namespace MoveShapeDemo
{
public class Broadcaster
{
/// <summary>
/// 延时加载的功能
/// </summary>
private readonly static Lazy<Broadcaster> _instance = new Lazy<Broadcaster>(() => new Broadcaster());
private readonly TimeSpan BroadcastInterval = TimeSpan.FromMilliseconds(40);
private readonly IHubContext _hubContext;
private Timer _broadcastLoop;
private ShapeModel _model;
private bool _modelUpdated; private Broadcaster()
{
// 获得对指定Hub连接的引用
_hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>();
_model = new ShapeModel();
_modelUpdated = false;
_broadcastLoop = new Timer(BroadcastShape, null, BroadcastInterval, BroadcastInterval);
} public static Broadcaster Instance
{
get { return _instance.Value; }
} /// <summary>
/// 将最新坐标广播给其它客户端(被定时器循环调用)
/// </summary>
/// <param name="state"></param>
private void BroadcastShape(object state)
{
if (_modelUpdated)
{
_hubContext.Clients.AllExcept(_model.LastUpdateBy).updateShape(_model);
_modelUpdated = false;
}
} public void UpdateShape(ShapeModel clientModel)
{
_model = clientModel;
_modelUpdated = true;
}
} /// <summary>
/// Hub的生命周期比较短(只有在需要的时候才会创建)
/// </summary>
public class MoveShapeHub : Hub
{
private Broadcaster _broadcaster; public MoveShapeHub() :
this(Broadcaster.Instance)
{ } public MoveShapeHub(Broadcaster broadcaster)
{
_broadcaster = broadcaster;
} public void UpdateModel(ShapeModel clientModel)
{
clientModel.LastUpdateBy = Context.ConnectionId; // 将原来的广播消息给其它客户端的代码交由Broadcaster来管理,
// 这样就能够避免只要有数据传入就立即广播给其它客户端的情况
// 出现。取而代之的是使用Timer类的定时广播功能,从而达到从
// 服务器这端节省资源的目的。
_broadcaster.UpdateShape(clientModel);
}
} public class ShapeModel
{
/// <summary>
/// 使用JsonProperty指定的名称来序列化该属性
/// </summary>
[JsonProperty("left")]
public double Left { get; set; } /// <summary>
/// 同上
/// </summary>
[JsonProperty("top")]
public double Top { get; set; } /// <summary>
/// 使用JsonIgnore表示序列化时忽略该属性
/// </summary>
[JsonIgnore]
public string LastUpdateBy { get; set; }
}

重新运行项目,其实运行效果和之前并没有什么两样,只是服务器端不再会接到客户端发来的数据后就立即广播给其它客户端,而是会做记录,等到计器器下一次起动广播时再把这个坐标广播给其它客户端,不过被广播的用户依然会有看PPT的感觉。

改进三:为客户端添加动画效果

现在我们还要做最后一点改动,那就是解决被移动的矩形看起来像PPT一样的问题,只里要将客户端声明的回调方法(updateShape)做适当的改动即可,代码如下所示。

// 声明的回调方法
moveShapeHub.client.updateShape = function (model) {
shapeModel = model; // 使用动画效果使得矩形被移动时看起来更平滑,
// duration:动画的持续时间
// queue:是否在效果队列中放置动画
$shape.animate(shapeModel, { duration: updateRate, queue: false });
};

使用SignalR实现即时通讯功能的更多相关文章

  1. MVC中使用SignalR打造酷炫实用的即时通讯功能附源码

    前言,现在这世道写篇帖子没个前言真不好意思发出来.本贴的主要内容来自于本人在之前项目中所开发的一个小功能,用于OA中的即时通讯.由于当时走的太急,忘记把代码拿出来.想想这已经是大半年前的事情了,时间过 ...

  2. MVC中使用SignalR打造酷炫实用的即时通讯功能(轉載)

    資料來源:http://www.fangsi.net/1144.html 前言,现在这世道写篇帖子没个前言真不好意思发出来.本贴的主要内容来自于本人在之前项目中所开发的一个小功能,用于OA中的即时通讯 ...

  3. [置顶] Xamarin android中使用signalr实现即时通讯

    前面几天也写了一些signalr的例子,不过都是在Web端,今天我就来实践一下如何在xamarin android中使用signalr,刚好工作中也用到了这个,也算是总结一下学到的东西吧,希望能帮助你 ...

  4. Android BLE与终端通信(四)——实现服务器与客户端即时通讯功能

    Android BLE与终端通信(四)--实现服务器与客户端即时通讯功能 前面几篇一直在讲一些基础,其实说实话,蓝牙主要为多的还是一些概念性的东西,当你把概念都熟悉了之后,你会很简单的就可以实现一些逻 ...

  5. Android WebSocket实现即时通讯功能

    最近做这个功能,分享一下.即时通讯(Instant Messaging)最重要的毫无疑问就是即时,不能有明显的延迟,要实现IM的功能其实并不难,目前有很多第三方,比如极光的JMessage,都比较容易 ...

  6. 黑科技!仅需 3 行代码,就能将 Gitter 集成到个人网站中,实现一个 IM 即时通讯聊天室功能?

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 高级架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  7. android环境下的即时通讯

    首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送 ...

  8. 用smack+openfire做即时通讯

    首发:个人博客 必须说明:smack最新的4.1.1,相对之前版本变化很大,而且资料缺乏,官方文档也不好,所以还是用老版本3.2.2吧.这篇博文中的代码是4.1.1版的,但不推荐用它.用openfir ...

  9. openfire+spark+smack实现即时通讯

    近公司项目需要用到即时通讯功能,经过调研发现openfire+spark+smack可以实现.在网上找了很久,资料都十分有限,即使有些朋友实现了也说的不清不楚.于是决定自己研究,耗时一周的时间实现了文 ...

随机推荐

  1. 深入浅出NodeJS——数据通信,NET模块运行机制

    互联网的运作,最根本的驱动就是信息的交互,NodeJS 在数据交互这一块做的很带感,异步编程让人很惬意,关于 NodeJS 的数据通信,最基础的两个模块是 NET 和 HTTP,前者是基于 TCP 的 ...

  2. 京东招聘Java开发人员

    软件开发工程师(JAVA) 岗位职责: 1. 负责京东核心业务系统的需求分析.设计.开发工作 2. 负责相关技术文档编写工作 3. 解决系统中的关键问题和技术难题 任职要求: 1. 踏实诚恳.责任心强 ...

  3. HTTP学习一:HTTP基础知识

    1 HTTP介绍 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议. 它的发展是万维网协会(World Wid ...

  4. 【Win10应用开发】自适应磁贴中的分组

    老周在上一篇文章中介绍过了自适应磁贴的基本结构,以及给大家演示了一些例子. 本文老周给大伙伴们说说自适应磁贴的另一个特点——分组呈现. 当磁贴的内容被分组后,每个组中的内容就会被视为一个整体.比如某磁 ...

  5. 推荐21款最佳 HTML5 网页游戏

    尽管 HTML5 的完全实现还有很长的路要走,但 HTML5 正在改变 Web,未来 HTML5 将把 Web 带入一个更加成熟和开放的应用平台.现在,越来越多的人尝试用 HTML5 来制作网页游戏等 ...

  6. 传智播客--XAML布局--连连看界面(小白内容)

    一个简单的10*10连连看,有100个格子,可以在XAML里面用ColumnDefinition和RowDefinition各写10组,但是这样效率会很慢,因此,可以采用动态生成的方式进行. publ ...

  7. MVC4做网站后台:模块管理1、修改模块信息

    网站可能会包含一些模块:像文章.产品.图片.留言等. 栏目模块主要实现功能,启用或禁用模块,模块权限设置,模块上传设置等. 权限设置和上传设置以后专门考虑,先来显示或禁用模块. 1.在顶部导航栏添加管 ...

  8. 一起学微软Power BI系列-官方文档-入门指南(5)探索数据奥秘

    我们几篇系列文章中,我们介绍了官方入门文档与获取数据等基本知识.今天继续给大家另外一个重点,探索数据奥秘.有了数据源,有了模型,下一步就是如何解析数据了.解析数据的过程需要很多综合技能,不仅仅是需要掌 ...

  9. 升级到Windows10

    1.Windows10的优点 2.需要安装的软件 实用软件: Firefox浏览器 Chrome浏览器 有道云笔记 Adobe Reader Adobe Flash Adobe PhotoShop 编 ...

  10. 安装Ubuntu时分区选择

    最近购买来一台二手笔记本.型号是:Dell Latitude D520.回来之后就装上来Ubuntu12.04,开始是安装的UbuntuKylin 13.04.不知道是机器配置不行,还是本身系统有点卡 ...