1.介绍

  我们知道传统的http采用的是“拉模型”,也就是每次请求,每次断开这种短请求模式,这种场景下,client是老大,server就像一个小乌龟任人摆布,
很显然,只有一方主动,这事情就没那么完美了,所以为了能够让server也能主动点,html5就应运而生了,或许大家都知道html5中有两种server的主动
模型,第一种叫做websockect,也就是基于tcp模式的双工通讯,还有一种叫做SSE,也就是客户端来订阅服务器的一种事件模型,当然了,在html5出
来之前,如果要做到服务器主动,我们只能采用变相的longpool和foreverframe勉强实现,而signalR这吊毛就是一个对他们进行了高层封装,也就是说
signalR会在这四种技术中根据浏览器和服务器设置采取最优的一种模式,废话不多说,我们快速建立一个例子。

2.快速搭建

1.引入dll

2.创建hub类(消息处理)

  1. using Microsoft.AspNet.SignalR;
  2. using Microsoft.AspNet.SignalR.Hubs;
  3. using ServiceStack.Redis;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.Linq;
  8. using System.Threading.Tasks;
  9. using System.Web;
  10.  
  11. namespace SignalRMvcDemo
  12. {
  13. [HubName("MessageHub")]
  14. public class MessageHub : Hub
  15. {
  16. //当前用户
  17. public static List<UserInfo> OnlineUsers = new List<UserInfo>(); // 在线用户列表
  18. RedisClient client = new RedisClient("192.168.10.134", , "", );
  19.  
  20. /// <summary>
  21. /// 登录连线
  22. /// </summary>
  23. /// <param name="userId">用户Id</param>
  24. /// <param name="userName">用户名</param>
  25. public void Register(string userName)
  26. {
  27. OnlineUsers = client.Get<List<UserInfo>>("list") ?? new List<UserInfo>();
  28. var connnectId = Context.ConnectionId;
  29. if (!OnlineUsers.Any(x => x.ConnectionId == connnectId))
  30. {
  31. //添加在线人员
  32. OnlineUsers.Add(new UserInfo
  33. {
  34. ConnectionId = connnectId,
  35. UserName = userName,
  36. LastLoginTime = DateTime.Now
  37. });
  38. }
  39. // 所有客户端同步在线用户
  40. Clients.All.onConnected(connnectId, userName, OnlineUsers);
  41. client.Set<List<UserInfo>>("list", OnlineUsers);
  42. }
  43.  
  44. /// <summary>
  45. /// 发送私聊
  46. /// </summary>
  47. /// <param name="toUserId">接收方用户ID</param>
  48. /// <param name="message">内容</param>
  49. public void SendPrivateMessage(string toConnectionId, string message)
  50. {
  51. OnlineUsers = client.Get<List<UserInfo>>("list") ?? new List<UserInfo>();
  52. var fromConnectionId = Context.ConnectionId;
  53.  
  54. var toUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == toConnectionId);
  55. var fromUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == fromConnectionId);
  56.  
  57. if (toUser != null)
  58. {
  59. Clients.Client(toUser.ConnectionId).receivePrivateMessage(fromUser.ConnectionId, fromUser.UserName, message);
  60. }
  61. else
  62. {
  63. //表示对方不在线
  64. Clients.Caller.absentSubscriber();
  65. }
  66. }
  67.  
  68. /// <summary>
  69. /// 全部发送
  70. /// </summary>
  71. /// <param name="message"></param>
  72. public void AllSend(string name, string message)
  73. {
  74. Clients.All.AllSend(name, message);
  75. }
  76.  
  77. /// <summary>
  78. /// 连线时调用
  79. /// </summary>
  80. /// <returns></returns>
  81. public override Task OnConnected()
  82. {
  83. //Console.WriteLine("客户端连接,连接ID是:{0},当前在线人数为{1}", Context.ConnectionId, OnlineUsers.Count + 1);
  84. return base.OnConnected();
  85. }
  86.  
  87. /// <summary>
  88. /// 断线时调用
  89. /// </summary>
  90. /// <param name="stopCalled"></param>
  91. /// <returns></returns>
  92. public override Task OnDisconnected(bool stopCalled)
  93. {
  94. OnlineUsers = client.Get<List<UserInfo>>("list")??new List<UserInfo>();
  95. var user = OnlineUsers.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId);
  96.  
  97. // 判断用户是否存在,存在则删除
  98. if (user == null)
  99. {
  100. return base.OnDisconnected(stopCalled);
  101. }
  102. // 删除用户
  103. OnlineUsers.Remove(user);
  104. Clients.All.onUserDisconnected(OnlineUsers); //调用客户端用户离线通知
  105. client.Set<List<UserInfo>>("list", OnlineUsers);
  106.  
  107. return base.OnDisconnected(stopCalled);
  108. }
  109.  
  110. /// <summary>
  111. /// 重新连接时调用
  112. /// </summary>
  113. /// <returns></returns>
  114. public override Task OnReconnected()
  115. {
  116. return base.OnReconnected();
  117. }
  118. }
  119.  
  120. public class UserInfo
  121. {
  122. public string ConnectionId { get; set; }
  123. public string UserName { get; set; }
  124. public DateTime LastLoginTime { get; set; }
  125. }
  126. }

3.Startup类(1.配置跨域 2.配置多实例)

  1. using System;
  2. using System.Threading.Tasks;
  3. using Microsoft.Owin;
  4. using Owin;
  5. using Microsoft.AspNet.SignalR;
  6. using Microsoft.Owin.Cors;
  7.  
  8. [assembly: OwinStartup(typeof(SignalRMvcDemo.StartupSignalR))]
  9.  
  10. namespace SignalRMvcDemo
  11. {
  12. public class StartupSignalR
  13. {
  14. public void Configuration(IAppBuilder app)
  15. {
  16. //允许CORS跨域
  17. app.UseCors(CorsOptions.AllowAll);
  18. #region Redis配置
  19. //添加redis
  20. RedisScaleoutConfiguration redisScaleoutConfiguration = new RedisScaleoutConfiguration("192.168.10.134", , "", "redis_signalr");
  21. //连接DB,默认为0
  22. redisScaleoutConfiguration.Database = ;
  23. //SignalR用Redis
  24. GlobalHost.DependencyResolver.UseRedis(redisScaleoutConfiguration);
  25. #endregion
  26. // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888
  27. app.MapSignalR();//启动SignalR
  28. }
  29. }
  30. }

4.前端调用(引用hub生产的js文件,前端方法名称要与后端一致)

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title></title>
  6. <meta charset="utf-8" />
  7. <link href="Content/bootstrap.min.css" rel="stylesheet" />
  8. <link href="Lib/toastr/toastr.min.css" rel="stylesheet" />
  9. </head>
  10. <body>
  11. <div class="panel panel-default">
  12. <div class="panel-body">
  13. <h1>分布式-消息推送测试</h1>
  14. </div>
  15. </div>
  16. <span>ConnectionId:</span>
  17. <input type="text" id="ConnectionId" readonly value="">
  18. <span>当前用户名称:</span>
  19. <input type="text" id="UserName" readonly value="">
  20. <hr>
  21. <span>在线用户数量:</span>
  22. <input type="text" id="userCount" readonly value="">
  23. <hr>
  24. <table class="table table-bordered">
  25. <thead>
  26. <tr>
  27. <th>ConnectionId</th>
  28. <th>UserName</th>
  29. </tr>
  30. </thead>
  31. <tbody id="tbody1"></tbody>
  32. </table>
  33. <span>接收用户:</span><select id="toUser"></select>
  34. <input type="text" id="message" />
  35. <input id="send" type="button" value="发送" />
  36. <input id="sendAll" type="button" value="发送消息(所有客户端)" />
  37. <script src="Scripts/jquery-1.10.2.min.js"></script>
  38. <script src="Lib/toastr/toastr.min.js"></script>
  39. <script src="Lib/iNotify/iNotify.js"></script>
  40. <script src="Scripts/bootstrap.min.js"></script>
  41. <script src="Scripts/jquery.signalR-2.2.2.js"></script>
  42. <script src='/SignalR/hubs'></script>
  43. <script type='text/javascript'>
  44. $(function () {
  45. $.connection.hub.url = 'http://localhost:10086/signalr';
  46. //引用自动生成的代理,MessageHub是HubName注解属性
  47. var work = $.connection.MessageHub;
  48.  
  49. //对应后端的SendPrivateMessage函数,消息接收函数
  50. work.client.receivePrivateMessage = function (connectionId, user, message) {
  51. //$('#messgaeInfo').append(message + '</br>');
  52. toastr.info('发送内容:' + message, "发送人:" + user)
  53. Notify.player();
  54. Notify.setTitle(true);
  55. Notify.setTitle('你有新的消息!');
  56. };
  57.  
  58. //对应后端的SendMessage函数,消息接收函数
  59. work.client.AllSend = function (name, message) {
  60. toastr.info('发送内容:' + message, "群发消息发生人:" + name)
  61. Notify.player();
  62. Notify.setTitle(true);
  63. Notify.setTitle('你有新的消息!');
  64. };
  65.  
  66. //后端SendLogin调用后,产生的loginUser回调
  67. work.client.onConnected = function (connnectId, userName, OnlineUsers) {
  68. reloadUser(OnlineUsers);
  69. };
  70. work.client.onUserDisconnected = function (OnlineUsers) {
  71. reloadUser(OnlineUsers);
  72. };
  73. //hub连接开启
  74. $.connection.hub.start().done(function () {
  75. $('#UserName').val(prompt('请输入昵称:', ''));
  76. var username = $('#UserName').val();
  77. $('#ConnectionId').val($.connection.MessageHub.connection.id);
  78. //发送上线信息
  79. work.server.register(username);
  80.  
  81. //点击按钮,发送消息
  82. $('#send').click(function () {
  83. var friend = $('#toUser').val();
  84. //调用后端函数,发送指定消息
  85. work.server.sendPrivateMessage(friend, $("#message").val());
  86. });
  87.  
  88. //点击按钮,发送消息
  89. $('#sendAll').click(function () {
  90. //调用后端函数,发送指定消息
  91. work.server.allSend($('#UserName').val(), $("#message").val());
  92. });
  93. });
  94. });
  95.  
  96. //重新加载用户列表
  97. var reloadUser = function (userlist) {
  98. $("#tbody1").empty();
  99. $("#toUser").empty();
  100. $("#userCount").val(userlist.length);
  101. for (i = 0; i < userlist.length; i++) {
  102. $("#tbody1").append("<tr><td>" + userlist[i].ConnectionId + "</td><td>" + userlist[i].UserName + "</td></tr>");
  103. $("#toUser").append("<option value=" + userlist[i].ConnectionId + ">" + userlist[i].ConnectionId + ':[' + userlist[i].UserName + "]</option>");
  104. }
  105. }
  106.  
  107. //toastr配置
  108. toastr.options = {
  109. closeButton: true,
  110. debug: false,
  111. progressBar: true,
  112. positionClass: "toast-bottom-right",
  113. onclick: null,
  114. showDuration: "300",
  115. hideDuration: "1000",
  116. timeOut: "5000",
  117. extendedTimeOut: "1000",
  118. showEasing: "swing",
  119. hideEasing: "linear",
  120. showMethod: "fadeIn",
  121. hideMethod: "fadeOut"
  122. };
  123.  
  124. //iNotify配置
  125. var Notify = new iNotify({
  126. audio: {
  127. file: ['Sound/msg.mp3']
  128. },
  129. });
  130. </script>
  131. </body>
  132. </html>

5.效果(支持跨域,需要有redis)

3.项目下载路径 https://github.com/lgxlsm/SignalRMvcDemo

SignalRMvc的简单例子的更多相关文章

  1. Hibernate4.2.4入门(一)——环境搭建和简单例子

    一.前言 发下牢骚,这段时间要做项目,又要学框架,搞得都没时间写笔记,但是觉得这知识学过还是要记录下.进入主题了 1.1.Hibernate简介 什么是Hibernate?Hibernate有什么用? ...

  2. AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答

    一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...

  3. spring mvc(注解)上传文件的简单例子

    spring mvc(注解)上传文件的简单例子,这有几个需要注意的地方1.form的enctype=”multipart/form-data” 这个是上传文件必须的2.applicationConte ...

  4. ko 简单例子

    Knockout是在下面三个核心功能是建立起来的: 监控属性(Observables)和依赖跟踪(Dependency tracking) 声明式绑定(Declarative bindings) 模板 ...

  5. mysql定时任务简单例子

    mysql定时任务简单例子 ? 1 2 3 4 5 6 7 8 9     如果要每30秒执行以下语句:   [sql] update userinfo set endtime = now() WHE ...

  6. java socket编程开发简单例子 与 nio非阻塞通道

    基本socket编程 1.以下只是简单例子,没有用多线程处理,只能一发一收(由于scan.nextLine()线程会进入等待状态),使用时可以根据具体项目功能进行优化处理 2.以下代码使用了1.8新特 ...

  7. 一个简单例子:贫血模型or领域模型

    转:一个简单例子:贫血模型or领域模型 贫血模型 我们首先用贫血模型来实现.所谓贫血模型就是模型对象之间存在完整的关联(可能存在多余的关联),但是对象除了get和set方外外几乎就没有其它的方法,整个 ...

  8. [转] 3个学习Socket编程的简单例子:TCP Server/Client, Select

    以前都是采用ACE的编写网络应用,最近由于工作需要,需要直接只用socket接口编写CS的代码,重新学习这方面的知识,给出自己所用到的3个简单例子,都是拷贝别人的程序.如果你能完全理解这3个例子,估计 ...

  9. jsonp的简单例子

    jsonp的简单例子 index.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8&q ...

随机推荐

  1. Python备份MySQL数据库【转】

    #!/usr/bin/env python # coding: utf- import os import time ''' defined variable ''' databases=['hch' ...

  2. 节流(Throttling)和去抖(Debouncing)详解

    这篇文章的作者是 David Corbacho,伦敦的一名前端开发工程师.之前我们有一篇关于”节流”和”去抖”的文章:The Difference Between Throttling and Deb ...

  3. 创建一个yum源,rpm安装二进制包

    作者:邓聪聪 安装mariadb vi /etc/yum.repos.d/mariadb.repo [mariadb]name=mariadbbaseurl=http://mirrors.neusof ...

  4. requests库入门07-patch请求

    使用data参数提交 设置邮件能见度,这个接口用来设置邮件是公共可见,还是私有的 import requests test_url = 'https://api.github.com' def get ...

  5. C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法

    有些成员变量的数据类型比较特别,它们的初始化方式也和普通数据类型的成员变量有所不同.这些特殊的类型的成员变量包括: a.引用 b.常量 c.静态 d.静态常量(整型) e.静态常量(非整型) 常量和引 ...

  6. boost.python入门教程 ----python 嵌入c++

    Python语言简介 Python是一种脚本语言.以开放的开发接口和独特的语法著称.尽管Python在国内引起注意只有几年的时间,但实际上Python出现于上世纪90年代(据www.python.or ...

  7. cocosCreater开发时遇到的问题

    生成vscode任务后无法编译: ctrl +p  -> 输入task compile 编译任务时提示 :由于使用任务版本 0.1.0,以下工作区文件夹将被忽略 这是cocos默认生成的code ...

  8. python操作三大主流数据库(7)python操作mongodb数据库①mongodb的安装和简单使用

    python操作mongodb数据库①mongodb的安装和简单使用 参考文档:中文版:http://www.mongoing.com/docs/crud.html英文版:https://docs.m ...

  9. Golang 优化之路-空结构[转]

    写在前面 开发 hashset 常用的套路: map[int]int8 map[int]bool 我们一般只用 map 的键来保存数据,值是没有用的.所以来缓存集合数据会造成内存浪费. 空对象 空对象 ...

  10. Maven安装与配置及使用

    下载及安装 官方下载地址:直达官网下载页面 进入下载页面后,根据你电脑所装jdk版本选择对应版本的maven进行下载. 我们可以看到该页上边红框内写明了,maven3.3版以上支持的是JDK1.7+的 ...