SignalRMvc的简单例子
1.介绍
我们知道传统的http采用的是“拉模型”,也就是每次请求,每次断开这种短请求模式,这种场景下,client是老大,server就像一个小乌龟任人摆布,
很显然,只有一方主动,这事情就没那么完美了,所以为了能够让server也能主动点,html5就应运而生了,或许大家都知道html5中有两种server的主动
模型,第一种叫做websockect,也就是基于tcp模式的双工通讯,还有一种叫做SSE,也就是客户端来订阅服务器的一种事件模型,当然了,在html5出
来之前,如果要做到服务器主动,我们只能采用变相的longpool和foreverframe勉强实现,而signalR这吊毛就是一个对他们进行了高层封装,也就是说
signalR会在这四种技术中根据浏览器和服务器设置采取最优的一种模式,废话不多说,我们快速建立一个例子。
2.快速搭建
1.引入dll
2.创建hub类(消息处理)
- using Microsoft.AspNet.SignalR;
- using Microsoft.AspNet.SignalR.Hubs;
- using ServiceStack.Redis;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Threading.Tasks;
- using System.Web;
- namespace SignalRMvcDemo
- {
- [HubName("MessageHub")]
- public class MessageHub : Hub
- {
- //当前用户
- public static List<UserInfo> OnlineUsers = new List<UserInfo>(); // 在线用户列表
- RedisClient client = new RedisClient("192.168.10.134", , "", );
- /// <summary>
- /// 登录连线
- /// </summary>
- /// <param name="userId">用户Id</param>
- /// <param name="userName">用户名</param>
- public void Register(string userName)
- {
- OnlineUsers = client.Get<List<UserInfo>>("list") ?? new List<UserInfo>();
- var connnectId = Context.ConnectionId;
- if (!OnlineUsers.Any(x => x.ConnectionId == connnectId))
- {
- //添加在线人员
- OnlineUsers.Add(new UserInfo
- {
- ConnectionId = connnectId,
- UserName = userName,
- LastLoginTime = DateTime.Now
- });
- }
- // 所有客户端同步在线用户
- Clients.All.onConnected(connnectId, userName, OnlineUsers);
- client.Set<List<UserInfo>>("list", OnlineUsers);
- }
- /// <summary>
- /// 发送私聊
- /// </summary>
- /// <param name="toUserId">接收方用户ID</param>
- /// <param name="message">内容</param>
- public void SendPrivateMessage(string toConnectionId, string message)
- {
- OnlineUsers = client.Get<List<UserInfo>>("list") ?? new List<UserInfo>();
- var fromConnectionId = Context.ConnectionId;
- var toUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == toConnectionId);
- var fromUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == fromConnectionId);
- if (toUser != null)
- {
- Clients.Client(toUser.ConnectionId).receivePrivateMessage(fromUser.ConnectionId, fromUser.UserName, message);
- }
- else
- {
- //表示对方不在线
- Clients.Caller.absentSubscriber();
- }
- }
- /// <summary>
- /// 全部发送
- /// </summary>
- /// <param name="message"></param>
- public void AllSend(string name, string message)
- {
- Clients.All.AllSend(name, message);
- }
- /// <summary>
- /// 连线时调用
- /// </summary>
- /// <returns></returns>
- public override Task OnConnected()
- {
- //Console.WriteLine("客户端连接,连接ID是:{0},当前在线人数为{1}", Context.ConnectionId, OnlineUsers.Count + 1);
- return base.OnConnected();
- }
- /// <summary>
- /// 断线时调用
- /// </summary>
- /// <param name="stopCalled"></param>
- /// <returns></returns>
- public override Task OnDisconnected(bool stopCalled)
- {
- OnlineUsers = client.Get<List<UserInfo>>("list")??new List<UserInfo>();
- var user = OnlineUsers.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId);
- // 判断用户是否存在,存在则删除
- if (user == null)
- {
- return base.OnDisconnected(stopCalled);
- }
- // 删除用户
- OnlineUsers.Remove(user);
- Clients.All.onUserDisconnected(OnlineUsers); //调用客户端用户离线通知
- client.Set<List<UserInfo>>("list", OnlineUsers);
- return base.OnDisconnected(stopCalled);
- }
- /// <summary>
- /// 重新连接时调用
- /// </summary>
- /// <returns></returns>
- public override Task OnReconnected()
- {
- return base.OnReconnected();
- }
- }
- public class UserInfo
- {
- public string ConnectionId { get; set; }
- public string UserName { get; set; }
- public DateTime LastLoginTime { get; set; }
- }
- }
3.Startup类(1.配置跨域 2.配置多实例)
- using System;
- using System.Threading.Tasks;
- using Microsoft.Owin;
- using Owin;
- using Microsoft.AspNet.SignalR;
- using Microsoft.Owin.Cors;
- [assembly: OwinStartup(typeof(SignalRMvcDemo.StartupSignalR))]
- namespace SignalRMvcDemo
- {
- public class StartupSignalR
- {
- public void Configuration(IAppBuilder app)
- {
- //允许CORS跨域
- app.UseCors(CorsOptions.AllowAll);
- #region Redis配置
- //添加redis
- RedisScaleoutConfiguration redisScaleoutConfiguration = new RedisScaleoutConfiguration("192.168.10.134", , "", "redis_signalr");
- //连接DB,默认为0
- redisScaleoutConfiguration.Database = ;
- //SignalR用Redis
- GlobalHost.DependencyResolver.UseRedis(redisScaleoutConfiguration);
- #endregion
- // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888
- app.MapSignalR();//启动SignalR
- }
- }
- }
4.前端调用(引用hub生产的js文件,前端方法名称要与后端一致)
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title></title>
- <meta charset="utf-8" />
- <link href="Content/bootstrap.min.css" rel="stylesheet" />
- <link href="Lib/toastr/toastr.min.css" rel="stylesheet" />
- </head>
- <body>
- <div class="panel panel-default">
- <div class="panel-body">
- <h1>分布式-消息推送测试</h1>
- </div>
- </div>
- <span>ConnectionId:</span>
- <input type="text" id="ConnectionId" readonly value="">
- <span>当前用户名称:</span>
- <input type="text" id="UserName" readonly value="">
- <hr>
- <span>在线用户数量:</span>
- <input type="text" id="userCount" readonly value="">
- <hr>
- <table class="table table-bordered">
- <thead>
- <tr>
- <th>ConnectionId</th>
- <th>UserName</th>
- </tr>
- </thead>
- <tbody id="tbody1"></tbody>
- </table>
- <span>接收用户:</span><select id="toUser"></select>
- <input type="text" id="message" />
- <input id="send" type="button" value="发送" />
- <input id="sendAll" type="button" value="发送消息(所有客户端)" />
- <script src="Scripts/jquery-1.10.2.min.js"></script>
- <script src="Lib/toastr/toastr.min.js"></script>
- <script src="Lib/iNotify/iNotify.js"></script>
- <script src="Scripts/bootstrap.min.js"></script>
- <script src="Scripts/jquery.signalR-2.2.2.js"></script>
- <script src='/SignalR/hubs'></script>
- <script type='text/javascript'>
- $(function () {
- $.connection.hub.url = 'http://localhost:10086/signalr';
- //引用自动生成的代理,MessageHub是HubName注解属性
- var work = $.connection.MessageHub;
- //对应后端的SendPrivateMessage函数,消息接收函数
- work.client.receivePrivateMessage = function (connectionId, user, message) {
- //$('#messgaeInfo').append(message + '</br>');
- toastr.info('发送内容:' + message, "发送人:" + user)
- Notify.player();
- Notify.setTitle(true);
- Notify.setTitle('你有新的消息!');
- };
- //对应后端的SendMessage函数,消息接收函数
- work.client.AllSend = function (name, message) {
- toastr.info('发送内容:' + message, "群发消息发生人:" + name)
- Notify.player();
- Notify.setTitle(true);
- Notify.setTitle('你有新的消息!');
- };
- //后端SendLogin调用后,产生的loginUser回调
- work.client.onConnected = function (connnectId, userName, OnlineUsers) {
- reloadUser(OnlineUsers);
- };
- work.client.onUserDisconnected = function (OnlineUsers) {
- reloadUser(OnlineUsers);
- };
- //hub连接开启
- $.connection.hub.start().done(function () {
- $('#UserName').val(prompt('请输入昵称:', ''));
- var username = $('#UserName').val();
- $('#ConnectionId').val($.connection.MessageHub.connection.id);
- //发送上线信息
- work.server.register(username);
- //点击按钮,发送消息
- $('#send').click(function () {
- var friend = $('#toUser').val();
- //调用后端函数,发送指定消息
- work.server.sendPrivateMessage(friend, $("#message").val());
- });
- //点击按钮,发送消息
- $('#sendAll').click(function () {
- //调用后端函数,发送指定消息
- work.server.allSend($('#UserName').val(), $("#message").val());
- });
- });
- });
- //重新加载用户列表
- var reloadUser = function (userlist) {
- $("#tbody1").empty();
- $("#toUser").empty();
- $("#userCount").val(userlist.length);
- for (i = 0; i < userlist.length; i++) {
- $("#tbody1").append("<tr><td>" + userlist[i].ConnectionId + "</td><td>" + userlist[i].UserName + "</td></tr>");
- $("#toUser").append("<option value=" + userlist[i].ConnectionId + ">" + userlist[i].ConnectionId + ':[' + userlist[i].UserName + "]</option>");
- }
- }
- //toastr配置
- toastr.options = {
- closeButton: true,
- debug: false,
- progressBar: true,
- positionClass: "toast-bottom-right",
- onclick: null,
- showDuration: "300",
- hideDuration: "1000",
- timeOut: "5000",
- extendedTimeOut: "1000",
- showEasing: "swing",
- hideEasing: "linear",
- showMethod: "fadeIn",
- hideMethod: "fadeOut"
- };
- //iNotify配置
- var Notify = new iNotify({
- audio: {
- file: ['Sound/msg.mp3']
- },
- });
- </script>
- </body>
- </html>
5.效果(支持跨域,需要有redis)
3.项目下载路径 https://github.com/lgxlsm/SignalRMvcDemo
SignalRMvc的简单例子的更多相关文章
- Hibernate4.2.4入门(一)——环境搭建和简单例子
一.前言 发下牢骚,这段时间要做项目,又要学框架,搞得都没时间写笔记,但是觉得这知识学过还是要记录下.进入主题了 1.1.Hibernate简介 什么是Hibernate?Hibernate有什么用? ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
- spring mvc(注解)上传文件的简单例子
spring mvc(注解)上传文件的简单例子,这有几个需要注意的地方1.form的enctype=”multipart/form-data” 这个是上传文件必须的2.applicationConte ...
- ko 简单例子
Knockout是在下面三个核心功能是建立起来的: 监控属性(Observables)和依赖跟踪(Dependency tracking) 声明式绑定(Declarative bindings) 模板 ...
- mysql定时任务简单例子
mysql定时任务简单例子 ? 1 2 3 4 5 6 7 8 9 如果要每30秒执行以下语句: [sql] update userinfo set endtime = now() WHE ...
- java socket编程开发简单例子 与 nio非阻塞通道
基本socket编程 1.以下只是简单例子,没有用多线程处理,只能一发一收(由于scan.nextLine()线程会进入等待状态),使用时可以根据具体项目功能进行优化处理 2.以下代码使用了1.8新特 ...
- 一个简单例子:贫血模型or领域模型
转:一个简单例子:贫血模型or领域模型 贫血模型 我们首先用贫血模型来实现.所谓贫血模型就是模型对象之间存在完整的关联(可能存在多余的关联),但是对象除了get和set方外外几乎就没有其它的方法,整个 ...
- [转] 3个学习Socket编程的简单例子:TCP Server/Client, Select
以前都是采用ACE的编写网络应用,最近由于工作需要,需要直接只用socket接口编写CS的代码,重新学习这方面的知识,给出自己所用到的3个简单例子,都是拷贝别人的程序.如果你能完全理解这3个例子,估计 ...
- jsonp的简单例子
jsonp的简单例子 index.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8&q ...
随机推荐
- Python备份MySQL数据库【转】
#!/usr/bin/env python # coding: utf- import os import time ''' defined variable ''' databases=['hch' ...
- 节流(Throttling)和去抖(Debouncing)详解
这篇文章的作者是 David Corbacho,伦敦的一名前端开发工程师.之前我们有一篇关于”节流”和”去抖”的文章:The Difference Between Throttling and Deb ...
- 创建一个yum源,rpm安装二进制包
作者:邓聪聪 安装mariadb vi /etc/yum.repos.d/mariadb.repo [mariadb]name=mariadbbaseurl=http://mirrors.neusof ...
- requests库入门07-patch请求
使用data参数提交 设置邮件能见度,这个接口用来设置邮件是公共可见,还是私有的 import requests test_url = 'https://api.github.com' def get ...
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
有些成员变量的数据类型比较特别,它们的初始化方式也和普通数据类型的成员变量有所不同.这些特殊的类型的成员变量包括: a.引用 b.常量 c.静态 d.静态常量(整型) e.静态常量(非整型) 常量和引 ...
- boost.python入门教程 ----python 嵌入c++
Python语言简介 Python是一种脚本语言.以开放的开发接口和独特的语法著称.尽管Python在国内引起注意只有几年的时间,但实际上Python出现于上世纪90年代(据www.python.or ...
- cocosCreater开发时遇到的问题
生成vscode任务后无法编译: ctrl +p -> 输入task compile 编译任务时提示 :由于使用任务版本 0.1.0,以下工作区文件夹将被忽略 这是cocos默认生成的code ...
- python操作三大主流数据库(7)python操作mongodb数据库①mongodb的安装和简单使用
python操作mongodb数据库①mongodb的安装和简单使用 参考文档:中文版:http://www.mongoing.com/docs/crud.html英文版:https://docs.m ...
- Golang 优化之路-空结构[转]
写在前面 开发 hashset 常用的套路: map[int]int8 map[int]bool 我们一般只用 map 的键来保存数据,值是没有用的.所以来缓存集合数据会造成内存浪费. 空对象 空对象 ...
- Maven安装与配置及使用
下载及安装 官方下载地址:直达官网下载页面 进入下载页面后,根据你电脑所装jdk版本选择对应版本的maven进行下载. 我们可以看到该页上边红框内写明了,maven3.3版以上支持的是JDK1.7+的 ...