NET中RabbitMQ的使用

https://www.cnblogs.com/xibei666/p/5931267.html

概述

  MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。AMQP(高级消息队列协议) 是一个异步消息传递所使用的应用层协议规范,作为线路层协议,而不是API(例如JMS),AMQP 客户端能够无视消息的来源任意发送和接受信息。AMQP的原始用途只是为金融界提供一个可以彼此协作的消息协议,而现在的目标则是为通用消息队列架构提供通用构建工具。因此,面向消息的中间件 (MOM)系统,例如发布/订阅队列,没有作为基本元素实现。AMQP当中有四个概念非常重要(一个虚拟主机持有一组交换机、队列和绑定):

virtual host,虚拟主机

exchange,交换机

queue,队列

binding,绑定

  更多理论性东西可以参考(在Windows上安装Rabbit MQ 指南),针对队列的讲解相当详细

Window下安装RabbbitMQ

文件下载安装

Rabbit MQ 是建立在强大的Erlang OTP平台上,因此安装Rabbit MQ的前提是安装Erlang。通过下面两个连接下载安装3.2.3 版本:

下载并安装 Erlang OTP For Windows (vR16B03)

运行安装 Rabbit MQ Server Windows Installer (v3.2.3)

默认安装的Rabbit MQ 监听端口是5672。先安装Erlang OTP后安装RabbitMQ,安装方式默认即可,RabbitMQ可以勾选安装后台服务、服务启动和停止等操作。

激活Rabbit MQ's Management Plugin

使用Rabbit MQ 管理插件,可以更好的可视化方式查看Rabbit MQ 服务器实例的状态,打开CMD命令,cd到安装目录(..\rabbitmq_server-3.2.3\sbin)下,输入下面的命令激活:

rabbitmq-plugins enable rabbitmq_management

要重启服务才能生效,可以执行

net stop RabbitMQ && net start RabbitMQ

输入网址,打开监控页面: http://localhost:15672 (默认账号和密码:guest 和guest)

配置RabbitMQ用户权限

RabbitMQ是存在用户权限的,默认是guest 密码也是guest,隶属于Administrator管理员下。现需要配置新用户和权限,继续打开CMD命令,cd到安装目录sbin下:

用户操作指令:

复制代码

::查询服务状态

rabbitmqctl status

::列举虚拟主机列表

rabbitmqctl list_vhosts

::列举用户列表

rabbitmqctl list_users

:: 添加用户和密码

rabbitmqctl add_user hao abc123

:: 设置权限

rabbitmqctl set_permissions yy "." "." ".*"

:: 分配用户组

rabbitmqctl set_user_tags yy administrator

:: 删除guest用户

rabbitmqctl delete_user guest

::修改用户密码

rabbitmqctl change_password {username} {newpassowrd}

复制代码

.NET中RabbitMQ使用

1、Nuget下载RabbitMQ.Client第三方类库,版本V3.6.5,高版本与.NET Framework 4.5有冲突,RabbitMQ Client地址

2、利用RabbitMQ Clinet类库编码(代码内容有注释,此处不做详细解释,文章后有完整代码的下载地址)

  <1>RabbitMQ的direct类型Exchange

   Producter发送消息代码:

复制代码

///



/// 连接配置

///

private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory(){

HostName ="192.168.1.8",UserName="hao",Password="abc123",Port= 5672

};

///



/// 路由名称

///

const string ExchangeName = "justin.exchange";

    //队列名称
const string QueueName = "justin.queue";
public static void DirectExchangeSendMsg()
{
using (IConnection conn = rabbitMqFactory.CreateConnection())
{
using (IModel channel = conn.CreateModel())
{
channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);
channel.QueueDeclare(QueueName, durable: true, autoDelete: false, exclusive: false, arguments: null);
channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName); var props = channel.CreateBasicProperties();
props.Persistent = true;
string vadata = Console.ReadLine();
while (vadata != "exit")
{
var msgBody = Encoding.UTF8.GetBytes(vadata);
channel.BasicPublish(exchange: ExchangeName, routingKey: QueueName, basicProperties: props, body: msgBody);
Console.WriteLine(string.Format("***发送时间:{0},发送完成,输入exit退出消息发送",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
vadata = Console.ReadLine();
}
}
}
}

复制代码

   

  Customer接收消息代码:

复制代码

///



/// 连接配置

///

private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory() {

HostName = "192.168.1.8", UserName = "hao", Password = "abc123", Port = 5672

};

///



/// 路由名称

///

const string ExchangeName = "justin.exchange";

    //队列名称
const string QueueName = "justin.queue";
public static void DirectAcceptExchange()
{
using (IConnection conn = rabbitMqFactory.CreateConnection())
{
using (IModel channel = conn.CreateModel())
{
channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);
channel.QueueDeclare(QueueName, durable: true, autoDelete: false, exclusive: false, arguments: null);
channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName);
while (true)
{
BasicGetResult msgResponse = channel.BasicGet(QueueName, noAck: true);
if (msgResponse != null)
{
var msgBody = Encoding.UTF8.GetString(msgResponse.Body);
Console.WriteLine(string.Format("***接收时间:{0},消息内容:{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),msgBody));
} //BasicGetResult msgResponse2 = channel.BasicGet(QueueName, noAck: false); ////process message ... //channel.BasicAck(msgResponse2.DeliveryTag, multiple: false);
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
}
}

复制代码

  

  但是这种处理速度较慢,因为循环线程等待。高效的接收消息的方式可以使用EventingBasicConsumer进行消息接收处理,修改代码内容如下:

复制代码

public static void DirectAcceptExchangeEvent()

{

using (IConnection conn = rabbitMqFactory.CreateConnection())

{

using (IModel channel = conn.CreateModel())

{

//channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);

channel.QueueDeclare(QueueName, durable: true, autoDelete: false, exclusive: false, arguments: null);

//channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName);

var consumer = new EventingBasicConsumer(channel);

consumer.Received += (model, ea) =>

{

var msgBody = Encoding.UTF8.GetString(ea.Body);

Console.WriteLine(string.Format("***接收时间:{0},消息内容:{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msgBody));

};

channel.BasicConsume(QueueName, noAck: true, consumer: consumer);

                //已过时用EventingBasicConsumer代替
//var consumer2 = new QueueingBasicConsumer(channel);
//channel.BasicConsume(QueueName, noAck: true, consumer: consumer);
//var msgResponse = consumer2.Queue.Dequeue(); //blocking
//var msgBody2 = Encoding.UTF8.GetString(msgResponse.Body); Console.WriteLine("按任意值,退出程序");
Console.ReadKey();
}
}
}

复制代码

  

  但是有些时候,消费者同一时间没有能力处理太多的业务,导致分配过来的队列消息不能及时处理完成,这个时候,我们可以设置BasicQos属性,告诉Broker同一时间将未处理完成的消息分配其他消费者,所以接收消息的地方需要略做修改,代码如下:

复制代码

public static void DirectAcceptExchangeTask()

{

using (IConnection conn = rabbitMqFactory.CreateConnection())

{

using (IModel channel = conn.CreateModel())

{

//channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);

channel.QueueDeclare(QueueName, durable: true, autoDelete: false, exclusive: false, arguments: null);

channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);//告诉broker同一时间只处理一个消息

//channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName);

var consumer = new EventingBasicConsumer(channel);

consumer.Received += (model, ea) =>

{

var msgBody = Encoding.UTF8.GetString(ea.Body);

Console.WriteLine(string.Format("***接收时间:{0},消息内容:{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msgBody));

int dots = msgBody.Split('.').Length - 1;

System.Threading.Thread.Sleep(dots * 1000);

Console.WriteLine(" [x] Done");

//处理完成,告诉Broker可以服务端可以删除消息,分配新的消息过来

channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);

};

//noAck设置false,告诉broker,发送消息之后,消息暂时不要删除,等消费者处理完成再说

channel.BasicConsume(QueueName, noAck: false, consumer: consumer);

        Console.WriteLine("按任意值,退出程序");
Console.ReadKey();
}
}

}

复制代码

  

  <2> RabbitMQ的Topic类型Exchange

  Producter 发送消息代码:

复制代码

///



/// 连接配置

///

private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory(){

HostName ="192.168.1.8",UserName="hao",Password="abc123",Port= 5672

};

///



/// 路由名称

///

const string TopExchangeName = "topic.justin.exchange";

    //队列名称
const string TopQueueName = "topic.justin.queue"; public static void TopicExchangeSendMsg()
{
using (IConnection conn = rabbitMqFactory.CreateConnection())
{
using (IModel channel = conn.CreateModel())
{
channel.ExchangeDeclare(TopExchangeName, "topic", durable: false, autoDelete: false, arguments: null);
channel.QueueDeclare(TopQueueName, durable: false, autoDelete: false, exclusive: false, arguments: null);
channel.QueueBind(TopQueueName, TopExchangeName, routingKey: TopQueueName);
//var props = channel.CreateBasicProperties();
//props.Persistent = true;
string vadata = Console.ReadLine();
while (vadata != "exit")
{
var msgBody = Encoding.UTF8.GetBytes(vadata);
channel.BasicPublish(exchange: TopExchangeName, routingKey: TopQueueName, basicProperties: null, body: msgBody);
Console.WriteLine(string.Format("***发送时间:{0},发送完成,输入exit退出消息发送", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
vadata = Console.ReadLine();
}
}
}
}

复制代码

  Customer接收消息代码:

复制代码

///



/// 连接配置

///

private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory() {

HostName = "192.168.1.8", UserName = "hao", Password = "abc123", Port = 5672

};

    /// <summary>
/// 路由名称
/// </summary>
const string TopExchangeName = "topic.justin.exchange"; //队列名称
const string TopQueueName = "topic.justin.queue"; public static void TopicAcceptExchange()
{
using (IConnection conn = rabbitMqFactory.CreateConnection())
{
using (IModel channel = conn.CreateModel())
{
channel.ExchangeDeclare(TopExchangeName, "topic", durable: false, autoDelete: false, arguments: null);
channel.QueueDeclare(TopQueueName, durable: false, autoDelete: false, exclusive: false, arguments: null);
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
channel.QueueBind(TopQueueName, TopExchangeName, routingKey: TopQueueName);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var msgBody = Encoding.UTF8.GetString(ea.Body);
Console.WriteLine(string.Format("***接收时间:{0},消息内容:{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msgBody));
int dots = msgBody.Split('.').Length - 1;
System.Threading.Thread.Sleep(dots * 1000);
Console.WriteLine(" [x] Done");
channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
};
channel.BasicConsume(TopQueueName, noAck: false, consumer: consumer); Console.WriteLine("按任意值,退出程序");
Console.ReadKey();
}
}
}

复制代码

参考资料:

在 Windows 上安装Rabbit MQ 指南(http://www.cnblogs.com/shanyou/p/4067250.html)

.NET 环境中使用RabbitMQ(http://www.cnblogs.com/yangecnu/p/4227535.html)

RabbitMQ Tutorial(http://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html)

源代码下载

知道的越多,不知道的也就越多,多多学习!

最新文章

  1. docker4dotnet #1 – 前世今生 &amp; 世界你好
  2. 01shell入门基础
  3. ListView优化-通用CommonAdapter编写备份
  4. Poj1852
  5. python抓取百度热词
  6. iOS开发——UI篇OC篇&amp;UITableView简单封装
  7. &quot;浏览器端&quot; 使用 commonjs 模块规范开发网页应用,像开发 node 那样开发网页应用
  8. 2017 清北济南考前刷题Day 3 afternoon
  9. 纯CSS垂直居中的四种解决方案
  10. SpringSecurity在Springboot下使用的初步体验
  11. 互联网最新kafka技术面试题含答案
  12. mysql常用操作小节
  13. 深挖JDK动态代理(一)
  14. spring cloud 配置文件application.yml和bootstrap.yml 的定位,区别和联系
  15. golang bug Unknown load command 0x32 (50)
  16. 眠眠interview Question
  17. iOS开发总结——协议代理的认识
  18. spring集成webSocket实现服务端向前端推送消息
  19. apache2.4配置
  20. 20145229吴姗珊《Java程序设计》第二周学习总结

热门文章

  1. win7 64位下使用regsvr32注册activex dll .
  2. wyx20162314实验报告二
  3. Metasploit – 内网连接
  4. m2eclipse插件——添加依赖不显示搜索结果
  5. 文件(1)--File
  6. java中Hashtable集合的常用方法
  7. struts2自定义Interceptor拦截器
  8. C++ 函数后面的const
  9. 使用SpringMVC报错 Error creating bean with name &#39;conversionService&#39; defined in class path resource [springmvc.xml]
  10. 关于jQuery中的offset()和position()