概述

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

  1. virtual host,虚拟主机
  2. exchange,交换机
  3. queue,队列
  4. binding,绑定

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

Window下安装RabbbitMQ

文件下载安装

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

  1. 下载并安装 Erlang OTP For Windows (vR16B03)
  2. 运行安装 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发送消息代码:

        /// <summary>
/// 连接配置
/// </summary>
private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory(){
HostName ="192.168.1.8",UserName="hao",Password="abc123",Port= 5672
};
/// <summary>
/// 路由名称
/// </summary>
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接收消息代码:

        /// <summary>
/// 连接配置
/// </summary>
private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory() {
HostName = "192.168.1.8", UserName = "hao", Password = "abc123", Port = 5672
};
/// <summary>
/// 路由名称
/// </summary>
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 发送消息代码:

        /// <summary>
/// 连接配置
/// </summary>
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 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接收消息代码:

        /// <summary>
/// 连接配置
/// </summary>
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)

源代码下载

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

RabbitMQ.Net 应用(1)的更多相关文章

  1. 消息队列——RabbitMQ学习笔记

    消息队列--RabbitMQ学习笔记 1. 写在前面 昨天简单学习了一个消息队列项目--RabbitMQ,今天趁热打铁,将学到的东西记录下来. 学习的资料主要是官网给出的6个基本的消息发送/接收模型, ...

  2. RabbitMq应用二

    在应用一中,基本的消息队列使用已经完成了,在实际项目中,一定会出现各种各样的需求和问题,rabbitmq内置的很多强大机制和功能会帮助我们解决很多的问题,下面就一个一个的一起学习一下. 消息响应机制 ...

  3. 如何优雅的使用RabbitMQ

    RabbitMQ无疑是目前最流行的消息队列之一,对各种语言环境的支持也很丰富,作为一个.NET developer有必要学习和了解这一工具.消息队列的使用场景大概有3种: 1.系统集成,分布式系统的设 ...

  4. RabbitMq应用一的补充(RabbitMQ的应用场景)

    直接进入正题. 一.异步处理 场景:发送手机验证码,邮件 传统古老处理方式如下图 这个流程,全部在主线程完成,注册->入库->发送邮件->发送短信,由于都在主线程,所以要等待每一步完 ...

  5. RabbitMq应用一

    RabbitMq应用一 RabbitMQ的具体概念,百度百科一下,我这里说一下我的理解,如果有少或者不对的地方,欢迎纠正和补充. 一个项目架构,小的时候,一般都是传统的单一网站系统,或者项目,三层架构 ...

  6. 缓存、队列(Memcached、redis、RabbitMQ)

    本章内容: Memcached 简介.安装.使用 Python 操作 Memcached 天生支持集群 redis 简介.安装.使用.实例 Python 操作 Redis String.Hash.Li ...

  7. 消息队列性能对比——ActiveMQ、RabbitMQ与ZeroMQ(译文)

    Dissecting Message Queues 概述: 我花了一些时间解剖各种库执行分布式消息.在这个分析中,我看了几个不同的方面,包括API特性,易于部署和维护,以及性能质量..消息队列已经被分 ...

  8. windows下 安装 rabbitMQ 及操作常用命令

    rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统.它遵循Mozilla Public License开源协议,采用 Erlang 实现的工业级的消息队列(MQ)服务器,Rab ...

  9. RabbitMQ + PHP (三)案例演示

    今天用一个简单的案例来实现 RabbitMQ + PHP 这个消息队列的运行机制. 主要分为两个部分: 第一:发送者(publisher) 第二:消费者(consumer) (一)生产者 (创建一个r ...

  10. RabbitMQ + PHP (二)AMQP拓展安装

    上篇说到了 RabbitMQ 的安装. 这次要在讲案例之前,需要安装PHP的AMQP扩展.不然可能会报以下两个错误. 1.Fatal error: Class 'AMQPConnection' not ...

随机推荐

  1. Could not determine own NN ID in namespace 'mycluster'

    执行hdfs namenode -bootstrapStandby的时候报错如下 19/03/24 18:00:48 ERROR namenode.NameNode: Failed to start ...

  2. Find the peace with yourself

    The purpose of being mature is to find the real calm and peace with yourself. Or you can say the tur ...

  3. opencv 基础数据结构

    头文件:cxcore/include/cxtypes.h CvPoint: CvPoint:(构造cvPoint) CvPoint2D32f: CvPoint3D32f: CvSize: CvSize ...

  4. mysql表操作与权限操作

    修改表ALTER TABLE 语法: . 修改表名 ALTER TABLE 表名 RENAME 新表名; . 增加字段 ALTER TABLE 表名 ADD 字段名 数据类型 [完整性约束条件…], ...

  5. Java 5- Java 修饰符

    Java 修饰符 Java语言提供了很多修饰符,主要分为以下两类: 访问修饰符 非访问修饰符 修饰符用来定义类.方法或者变量,通常放在语句的最前端.我们通过下面的例子来说明: public class ...

  6. for循环中进行联网请求数据、for循环中进行异步数据操作,数据排序错乱问题解决;

    for循环中进行联网请求数据,由于网络请求是异步的,第一个网络请求还没有回调,第二次第三次以及后续的网络请求又已经发出去了,有可能后续的网络请求会先回调:这时我们接收到的数据的排序就会错乱:怎么才能让 ...

  7. .NET Core和.NET Standard

    作为.NET家族的最新成员,有很多关于.NET Core和.NET Standard的误解,以及它们于.NET Framework之间的区别.在这篇文章,我会准确的解释他们究竟是什么,并看看何时应选择 ...

  8. 微信小程序奇奇怪怪的语法

    这... <view class="body"> <view class="nav bc_white"> <view class= ...

  9. TIDB-cenos7开发环境搭建

    1.安装centos7,注意要安装桌面,如果最小化安装,无法使用IDE了 关闭防火墙或者打开4000端口 systemctl stop firewalld.service #停止firewall sy ...

  10. [转]asp+oracle分页

    PageSize:每页显示的记录数.PageCount:根据用户设定好的PageSize和表中的总记录数,系统自动算出总页数.RecordCount:表中的总记录数.AbsolutePage:表示当前 ...