一、概述

本教程主要阐释了如何利用SignalR与消息队列的结合,实现不同客户端的交互

  • SignalR如何和消息队列交互(暂使用ActiveMQ消息队列)
  • SignalR寄宿在web中和其他SignalR、控制台客户端交互。
  • SignalR单独寄宿在控制台中和其他SignalR、控制台客户端交互。

下面屏幕截图展示了各个客户端通过ActiveMQ相互通信

  1、SignalR寄宿在web:

  2、SignalR寄宿在控制台中,web客户端调用SignalR,读者自行测试。

工程目录:

一、创建项目

  1、创建生产者项目,该项目要是通过控制台输入消息,发送到消息队列

    创建控制台应用程序命名为ActiveMQNetProcucer,然后用包管理器安装ActiveMQ的.Net客户端

    Install-Package Apache.NMS.ActiveMQ

    主要代码如下:

 using Apache.NMS;
using Apache.NMS.ActiveMQ;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ActiveMQNet
{
class Program
{
static IConnectionFactory _factory = null;
static IConnection _connection = null;
static ITextMessage _message = null; static void Main(string[] args)
{
//创建工厂
_factory = new ConnectionFactory("tcp://127.0.0.1:61616/"); try
{
//创建连接
using (_connection = _factory.CreateConnection())
{
//创建会话
using (ISession session = _connection.CreateSession())
{
//创建一个主题
IDestination destination = new Apache.NMS.ActiveMQ.Commands.ActiveMQTopic("topic"); //创建生产者
IMessageProducer producer = session.CreateProducer(destination); Console.WriteLine("Please enter any key to continue! ");
Console.ReadKey();
Console.WriteLine("Sending: "); //创建一个文本消息
_message = producer.CreateTextMessage("Hello AcitveMQ...."); //发送消息
producer.Send(_message, MsgDeliveryMode.NonPersistent, MsgPriority.Normal, TimeSpan.MinValue);
while (true)
{
var msg = Console.ReadLine();
_message = producer.CreateTextMessage(msg);
producer.Send(_message, MsgDeliveryMode.NonPersistent, MsgPriority.Normal, TimeSpan.MinValue);
} }
} }
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
} Console.ReadLine(); }
}
}

  2、创建消费者项目,该项目主要是订阅消息队列中的消息  

    创建控制台应用程序命名为ActiveMQNetCustomer,然后用包管理器安装ActiveMQ的.Net客户端

    Install-Package Apache.NMS.ActiveMQ

    主要代码:

 using Apache.NMS;
using Apache.NMS.ActiveMQ;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ActiveMQNetCustomer
{
class Program
{
static IConnectionFactory _factory = null; static void Main(string[] args)
{
try
{
//创建连接工厂
_factory = new ConnectionFactory("tcp://127.0.0.1:61616/");
//创建连接
using (IConnection conn = _factory.CreateConnection())
{
//设置客户端ID
// conn.ClientId = "Customer";
conn.Start();
//创建会话
using (ISession session = conn.CreateSession())
{
//创建主题
var topic = new Apache.NMS.ActiveMQ.Commands.ActiveMQTopic("topic"); //创建消费者
IMessageConsumer consumer = session.CreateDurableConsumer(topic, "Customer", null, false); //注册监听事件
consumer.Listener += new MessageListener(consumer_Listener); //这句代码非常重要,
//这里没有read方法,Session会话会被关闭,那么消费者将监听不到生产者的消息
Console.Read();
} //关闭连接
conn.Stop();
conn.Close();
} }
catch (Exception ex)
{
Console.Write(ex.ToString());
} } /// <summary>
/// 消费监听事件
/// </summary>
/// <param name="message"></param>
static void consumer_Listener(IMessage message)
{
ITextMessage msg = (ITextMessage)message;
Console.WriteLine("Receive: " + msg.Text);
}
}
}

  3、创建包装ActiveMQ生产者和消费者项目,供SignalR.ActiveMQ.WebHost项目使用,来发布消息和订阅消息

    创建类库项目Signalr.ActiveMQ,然后用包管理器安装ActiveMQ的.Net客户端

    Install-Package Apache.NMS.ActiveMQ

    主要代码;

    生产者类:创建单实例生产者对象调用Send发放,发送消息到ActiveMQ消息队列    

using Apache.NMS;
using Apache.NMS.ActiveMQ;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Signalr.ActiveMQ
{
public class Procucer
{
private IMessageProducer producer;
private static Procucer instance=null;
private Procucer(string customerId,string address)
{
instance = this;
//创建工厂
IConnectionFactory _factory = new ConnectionFactory("tcp://127.0.0.1:61616/"); try
{
//创建连接
IConnection _connection = _factory.CreateConnection();
{
//创建会话
ISession session = _connection.CreateSession();
{
//创建一个主题
IDestination destination = new Apache.NMS.ActiveMQ.Commands.ActiveMQTopic("topic"); //创建生产者
producer = session.CreateProducer(destination); Console.WriteLine("Please enter any key to continue! ");
// Console.ReadKey();
Console.WriteLine("Sending: "); }
} }
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
} //Console.ReadLine();
} public static Procucer GetInstance(string customerId="",string address= "tcp://127.0.0.1:61616/")
{
if (instance == null)
instance = new Procucer(customerId, address);
return instance;
} public void Send(string msg)
{
//创建一个文本消息
ITextMessage _message = producer.CreateTextMessage(msg);
//发送消息
producer.Send(_message, MsgDeliveryMode.NonPersistent, MsgPriority.Normal, TimeSpan.MinValue);
}
}
}

    消费者类:启用单独的线程监听消息队列中的消息,当监听到消息后 广播给所有的 SinglaR客户端,其中静态属性Clients保存了所有的SinglaR客户端,当SinglaR客户端连接或者断开的时候会更新Clients属性详细代码在SignalR.ActiveMQ.WebHost中的 MyHub文件中。为了阻止当前线程退出调用了 System.Threading.Thread.CurrentThread.Join();阻塞当前线程,避免当web中方法执行完毕后对象被回收,起不到监听消息队列的作用。

using Apache.NMS;
using Apache.NMS.ActiveMQ;
using Microsoft.AspNet.SignalR.Hubs;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web; namespace SignalR.ActiveMQ
{
public class Customer
{
private static object lockObj = new object();
private static IHubCallerConnectionContext<dynamic> _clients;
public static IHubCallerConnectionContext<dynamic> Clients
{
get { return _clients; }
set
{
lock (lockObj)
{
_clients = value;
}
}
}
public static void Run(string cutomerId="",string address= "tcp://127.0.0.1:61616/")
{
System.Threading.Thread t = new System.Threading.Thread(() =>
{
try
{
//创建连接工厂
IConnectionFactory _factory = new ConnectionFactory(address);
//创建连接
using (IConnection conn = _factory.CreateConnection())
{
//设置客户端ID
conn.ClientId = cutomerId;
conn.Start();
//创建会话
using (ISession session = conn.CreateSession())
{
//创建主题
var topic = new Apache.NMS.ActiveMQ.Commands.ActiveMQTopic("topic"); //创建消费者
IMessageConsumer consumer = session.CreateDurableConsumer(topic, "Customer", null, false); //注册监听事件
consumer.Listener += new MessageListener(consumer_Listener); //阻塞当前线程,监听消息
System.Threading.Thread.CurrentThread.Join();
}
//关闭连接
conn.Stop();
conn.Close();
} }
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
Console.WriteLine(ex.ToString());
} }); t.Start();
}
static void consumer_Listener(IMessage message)
{
ITextMessage msg = (ITextMessage)message;
if (Clients != null)
{
Clients.All.broadcastMessage(msg.Text);
}
Debug.WriteLine("Receive: " + msg.Text);
Console.WriteLine("Receive: " + msg.Text);
}
}
}

  4、创建web自宿主的SignalR项目,该项目既发布消息,也订阅消息

    创建MVC项目SignalR.ActiveMQ.WebHost,然后用包管理器安装ActiveMQ的.Net客户端

    Install-Package Apache.NMS.ActiveMQ

    创建SignalR的hub:当有客户端连接或者断开的时候更新Customer.Clients 静态属性,保存所有的SignalR客户端。

    web端通过调用代理的Send方法发送消息到消息队列。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using Signalr.ActiveMQ;
using System.Threading.Tasks; namespace SignalR.ActiveMQ.Sample.Signal.Class
{
public class chatHub : Hub
{
public void Send(string clientName, string message)
{
Procucer.GetInstance().Send(message);
}
public override Task OnConnected()
{
Customer.Clients = this.Clients;
return base.OnConnected();
} public override Task OnDisconnected(bool stopCalled)
{
Customer.Clients = this.Clients;
return base.OnDisconnected(stopCalled);
}
}
}

    Startup类中启动消费者监听线程,调用的项目Signalr.ActiveMQ中的Customer.Run()方法:

using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Owin;
using SignalR.ActiveMQ; [assembly: OwinStartupAttribute(typeof(SignalR.ActiveMQ.Sample.Startup))]
namespace SignalR.ActiveMQ.Sample
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR(); Customer.Run();//启动消费者监听线程
}
}
}

二、启动顺序:

1、启动ActiveMQ程序 可参考  http://www.cnblogs.com/xwdreamer/archive/2012/02/21/2360818.html

2、启动ActiveMQNetProcucer项目

3、ActiveMQNetCustomer项目

4、启动SignalR.ActiveMQ.WebHost,开多个浏览器窗口,模拟多个SignalR客户端

三、SignalR宿主和web客户端分离两个项目 

Signalr.ActiveMQ.SelfHost 用控制台寄宿SignalR提供的服务供Signalr.ActiveMQ.Web使用

Signalr.ActiveMQ.Web 通过chart.html调用Signalr.ActiveMQ.SelfHost的服务

Signalr.ActiveMQ.SelfHost 和SignalR.ActiveMQ.WebHost不能同时启动,现在两个项目绑定到了同一个端口。

四、测试

  在生产者窗口中输入消息回车,观察其他客户端的变化

在Singlar的web客户端发送消息,观察其他客户端的变化

源代码:https://github.com/zhaoyingju/SignalrActiveMQ.git

转自:https://www.cnblogs.com/zhyj/p/5071447.html

【转】SignalR与ActiveMQ结合构建实时通信的更多相关文章

  1. SignalR与ActiveMQ结合构建实时通信

    一.概述 本教程主要阐释了如何利用SignalR与消息队列的结合,实现不同客户端的交互 SignalR如何和消息队列交互(暂使用ActiveMQ消息队列) SignalR寄宿在web中和其他Signa ...

  2. SignalR与ActiveMQ

    SignalR与ActiveMQ结合构建实时通信   一.概述 本教程主要阐释了如何利用SignalR与消息队列的结合,实现不同客户端的交互 SignalR如何和消息队列交互(暂使用ActiveMQ消 ...

  3. asp.net core 中的SignalR与web前端进行实时通信

    一.介绍 SignalR是.net 开源库,用于构建需要实时进行用户交互和数据更新的web应用,如在线聊天,游戏,天气等实时应用程序,且简化了构建实时应用的过程,包括服务端库和js端库,继承了数种常见 ...

  4. SignalR实现服务器与客户端的实时通信

    百度百科给它的定义 实现实时通信.什么是实时通信的Web呢?就是让客户端(Web页面)和服务器端可以互相通知消息及调用方法,当然这是实时操作的. WebSockets是HTML5提供的新的API,可以 ...

  5. ActiveMQ系列之四:用ActiveMQ构建应用

    Broker:相当于一个ActiveMQ服务器实例 命令行启动参数示例如下: 1:activemq start :使用默认的activemq.xml来启动 2:activemq start xbean ...

  6. 分布式-信息方式-ActiveMQ构建应用

                                                     ActivemQ构建应用Broker:相当于一个 ActiveMQ服务器实例命令行启动参数示例如下:1 ...

  7. ASP.NET SignalR入门

    前言 之前在培训ASP.NET WebAPI的时候有提过SignalR这个技术,但当时只是讲了是用来做什么的,并没有多说.因为自己也是画图找资料的时候见到的.后来当一直关注的前端大神贤心发布LayIM ...

  8. SignalR来做实时Web聊天

    本章和大家分享的内容是使用Signal R框架创建个简易的群聊功能,主要讲解如何在.Net的MVC中使用这个框架,由于这个项目有官方文档(当然全英文),后面也不打算写分享篇了,主要目的是让朋友们在需要 ...

  9. 【转】SignalR来做实时Web聊天

    本章和大家分享的内容是使用Signal R框架创建个简易的群聊功能,主要讲解如何在.Net的MVC中使用这个框架,由于这个项目有官方文档(当然全英文),后面也不打算写分享篇了,主要目的是让朋友们在需要 ...

随机推荐

  1. Scratch编程:打猎(十)

    “ 上节课的内容全部掌握了吗?反复练习了没有,编程最好的学习方法就是练习.练习.再练习.一定要记得多动手.多动脑筋哦~~” 01 — 游戏介绍 这节我们实现一个消灭猎物的射击游戏. 02 — 设计思路 ...

  2. jquery 如何获取select 选中项的下一个选项的值

    <select> <option value="1" selected="selected">a</option> < ...

  3. git clone一个仓库下的单个文件【记录】

    注意:本方法会下载整个项目,但是,最后出现在本地项目文件下里只有需要的那个文件夹存在.类似先下载,再过滤. 有时候因为需要我们只想gitclone 下仓库的单个或多个文件夹,而不是全部的仓库内容,这样 ...

  4. [洛谷P5323][BJOI2019]光线

    题目大意:有$n$层玻璃,每层玻璃会让$a\%$的光通过,并把$b\%$的光反射.有一束光从左向右射过,问多少的光可以透过这$n$层玻璃 题解:事实上会发现,可以把连续的几层玻璃合成一层玻璃,但是要注 ...

  5. Codechef TSUM2 Sum on Tree 点分治、李超线段树

    传送门 点分治模板题都不会迟早要完 发现这道题需要统计所有路径的信息,考虑点分治统计路径信息. 点分治之后,因为路径是有向的,所以对于每一条路径都有向上和向下的两种.那么如果一条向上的路径,点数为\( ...

  6. 递归在JavaScript中的应用实例

    递归 适用的必要条件:①过程的描述中包含它自身②有明确的结束递归的条件. 主要思路:在每一次调用自己时,使用相同的解决问题的方法,但调用的参数每次不同(有规律的变化),使用一个终止处理(结束递归)的条 ...

  7. 全栈项目|小书架|服务器开发-NodeJS 使用 JWT 实现登录认证

    通过这篇 全栈项目|小书架|服务器开发-JWT 详解 文章我们对JWT有了深入的了解,那么接下来介绍JWT如何在项目中使用. 安装 $ npm install jsonwebtoken 生成 Toke ...

  8. Unity3D 跨平台原理

    Unity3D的跨平台原理核心在于对指令集CIL(通用中间语言)的应用. 机理 首先需要知道,Unity中的Mono是基于 通用语言架构(Common Language Infrastructure, ...

  9. 转 js一个简单实用的弹出层

      关闭 点击查看 >> <html> <head> <title>新文件标题</title> <script type=" ...

  10. Python 3 MySQL数据库操作

    import pymysql class Mysql_db(): def __init__(self,ip,username,password,db_name,table_name): self.ip ...