NET下RabbitMQ实践[示例篇]
在上一篇文章中,介绍了在window环境下安装erlang,rabbitmq-server,以免配置用户,权限,虚拟机等内容。
今天将会介绍如果使用rabbitmq进行简单的消息入队,出队操作,因为本文演示的环境要用到上文中配置的环境,所以要运行本文sample,请先按上一篇中完成相应环境配置。
首先,我们下载官方的.net客户端软件,链接:http://www.rabbitmq.com/dotnet.html
下载并安装之后,将安装目录下的这两个DLL文件复制到我们示例项目中,并添加引用:
RabbitMQ.Client.dll //基于的发布订阅消息的功能类
RabbitMQ.ServiceModel.dll //包括基于WCF方式发布订阅服务模型类
如下图:

接着,我们创建两个类,一个是ProducerMQ.cs(用于产生消息),一个是CustmerMq.cs(用于消费消息),代码如下:
首先是ProducerMQ:
public class ProducerMQ
{
public static void InitProducerMQ()
{
Uri uri = new Uri("amqp://10.0.4.85:5672/");
string exchange = "ex1";
string exchangeType = "direct";
string routingKey = "m1";
bool persistMode = true;
ConnectionFactory cf = new ConnectionFactory();
cf.UserName = "daizhj";
cf.Password = "617595";
cf.VirtualHost = "dnt_mq";
cf.RequestedHeartbeat = 0;
cf.Endpoint = new AmqpTcpEndpoint(uri);
using (IConnection conn = cf.CreateConnection())
{
using (IModel ch = conn.CreateModel())
{
if (exchangeType != null)
{
ch.ExchangeDeclare(exchange, exchangeType);//,true,true,false,false, true,null);
ch.QueueDeclare("q1", true);//true, true, true, false, false, null);
ch.QueueBind("q1", "ex1", "m1", false, null);
}
IMapMessageBuilder b = new MapMessageBuilder(ch);
IDictionary target = b.Headers;
target["header"] = "hello world";
IDictionary targetBody = b.Body;
targetBody["body"] = "daizhj";
if (persistMode)
{
((IBasicProperties)b.GetContentHeader()).DeliveryMode = 2;
}
ch.BasicPublish(exchange, routingKey,
(IBasicProperties)b.GetContentHeader(),
b.GetContentBody()); }
}
}
}
下面对上面代码进行说明:
1. 定义要链接的rabbitmq-server地址(基于amqp协议):
Uri uri = new Uri("amqp://10.0.4.85:5672/");
2. 定义交换方式
string exchange = "ex1";
string exchangeType = "direct";
string routingKey = "m1";
说明:rabbitmq交换方式分为三种,分别是:
Direct Exchange – 处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “dog”,则只有被标记为“dog”的消息才被转发,不会转发dog.puppy,也不会转发dog.guard,只会转发dog。
Fanout Exchange – 不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。
Topic Exchange – 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.*” 只会匹配到“audit.irs”。
更多内容参见:RabbitMQ 三种Exchange
3. 是否对消息队列持久化保存
bool persistMode = true;
4. 使用ConnectionFactory创建连接,虽然创建时指定了多个server address,但每个connection只与一个物理的server进行连接。
ConnectionFactory cf = new ConnectionFactory();
//使用前文的配置环境信息
cf.UserName = "daizhj";
cf.Password = "617595";
cf.VirtualHost = "dnt_mq";
cf.RequestedHeartbeat = 0;
cf.Endpoint = new AmqpTcpEndpoint(uri);
5. 实例化IConnection对象,并设置交换方式
using (IConnection conn = cf.CreateConnection())
{
using (IModel ch = conn.CreateModel())
{
if (exchangeType != null)
{
ch.ExchangeDeclare(exchange, exchangeType);//,true,true,false,false, true,null);
ch.QueueDeclare("q1", true);//true, true, true, false, false, null);
ch.QueueBind("q1", "ex1", "m1", false, null);
}
....
6. 构造消息实体对象并发布到消息队列上:
IMapMessageBuilder b = new MapMessageBuilder(ch);
IDictionary target = b.Headers;
target["header"] = "hello world";
IDictionary targetBody = b.Body;
targetBody["body"] = "daizhj";
if (persistMode)
{
((IBasicProperties)b.GetContentHeader()).DeliveryMode = 2;
}
//简单发布方式
ch.BasicPublish(exchange, routingKey,
(IBasicProperties)b.GetContentHeader(),
b.GetContentBody());
这样就完成了单条消息的发布。
下面是CustmerMq.cs(用于消费消息)实例代码:
public class CustmerMq
{
public static int InitCustmerMq()
{
string exchange = "ex1";
string exchangeType = "direct";
string routingKey = "m1"; string serverAddress = "10.0.4.85:5672";
ConnectionFactory cf = new ConnectionFactory();
cf.Address = serverAddress;
cf.UserName = "daizhj";
cf.Password = "617595";
cf.VirtualHost = "dnt_mq";
cf.RequestedHeartbeat = 0;
可以看出上面的代码与 ProducerMQ的开头代码类似,下面使用ConnectionFactory来构造链接并接收队列消息:
using (IConnection conn = cf.CreateConnection())
{
using (IModel ch = conn.CreateModel())
{
//普通使用方式BasicGet
//noAck = true,不需要回复,接收到消息后,queue上的消息就会清除
//noAck = false,需要回复,接收到消息后,queue上的消息不会被清除,直到调用channel.basicAck(deliveryTag, false); queue上的消息才会被清除 而且,在当前连接断开以前,其它客户端将不能收到此queue上的消息
BasicGetResult res = ch.BasicGet("q1", false/*noAck*/);
if (res != null)
{
bool t = res.Redelivered;
t = true;
Console.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(res.Body));
ch.BasicAck(res.DeliveryTag, false);
}
else
{
Console.WriteLine("No message!");
}
上面代码比较简单,主要是使用BasicGetResult来进行简单的消息接收,并使用BasicAck方式来告之是否从队列中移除该条消息。这一点很重要,因为在某些应用场景下,比如从队列中获取消息并用它来操作数据库或日志文件时,如果出现操作失败时,则该条消息应该保留在队列中,只到操作成功时才从队列中移除。
当然上面操作只是用于单条数据操作,如果要遍历队列中所有消息,则需要使用如下方式:
while (true)
{
BasicGetResult res = ch.BasicGet("q1", false/*noAck*/);
if (res != null)
{
try
{
bool t = res.Redelivered;
t = true;
Console.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(res.Body));
ch.BasicAck(res.DeliveryTag, false);
}
catch { }
}
else
break;
}
另外,在rabbitmq中,获取消息可以使用两种方式,一种是上面提到的主动获取,另一种是基于订阅模式,即让当前获取消息的线程阻塞,用于绑定到指定的队列上,当有新的消息入队之后,该阻塞线程会被运行,从队列中获取新入队的消息,形如:
//第二种取法QueueingBasicConsumer基于订阅模式
QueueingBasicConsumer consumer = new QueueingBasicConsumer(ch);
ch.BasicConsume("q1", false, null, consumer);
while (true)
{
try
{
BasicDeliverEventArgs e = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
IBasicProperties props = e.BasicProperties;
byte[] body = e.Body;
Console.WriteLine(System.Text.Encoding.UTF8.GetString(body));
//ch.BasicAck(e.DeliveryTag, true);
ProcessRemainMessage();
}
catch (EndOfStreamException ex)
{
//The consumer was removed, either through channel or connection closure, or through the action of IModel.BasicCancel().
Console.WriteLine(ex.ToString());
break;
}
}
这样,就完成了一个简单的发布,消费消息的示例。在接下来的文章中,将会介绍如果基于WCF来发布RABBITMQ服务,敬请关注:)
NET下RabbitMQ实践[示例篇]的更多相关文章
- NET下RabbitMQ实践[配置篇]
这个系列目前计划写四篇,分别是配置,示例,WCF发布,实战.当然不排除加餐情况. 介绍: rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统.他遵循Mozilla Publi ...
- NET下RabbitMQ实践[实战篇]
之前的文章中,介绍了如何将RabbitMQ以WCF方式进行发布.今天就介绍一下我们产品中如何使用RabbitMQ的! 在Discuz!NT企业版中,提供了对HTTP错误日志的记录功能 ...
- NET下RabbitMQ实践[WCF发布篇]
在之前的两篇文章中,主要介绍了RabbitMQ环境配置,简单示例的编写.今天将会介绍如何使用WCF将RabbitMQ列队以服务的方式进行发布. 注:因为RabbitMQ的官方.net ...
- 实践详细篇-Windows下使用VS2015编译的Caffe训练mnist数据集
上一篇记录的是学习caffe前的环境准备以及如何创建好自己需要的caffe版本.这一篇记录的是如何使用编译好的caffe做训练mnist数据集,步骤编号延用上一篇 <实践详细篇-Windows下 ...
- 实践详细篇-Windows下使用Caffe训练自己的Caffemodel数据集并进行图像分类
三:使用Caffe训练Caffemodel并进行图像分类 上一篇记录的是如何使用别人训练好的MNIST数据做训练测试.上手操作一边后大致了解了配置文件属性.这一篇记录如何使用自己准备的图片素材做图像分 ...
- Python操作rabbitmq 实践笔记
发布/订阅 系统 1.基本用法 生产者 import pika import sys username = 'wt' #指定远程rabbitmq的用户名密码 pwd = ' user_pwd = p ...
- Tree-Shaking性能优化实践 - 原理篇
Tree-Shaking性能优化实践 - 原理篇 一. 什么是Tree-shaking 先来看一下Tree-shaking原始的本意 上图形象的解释了Tree-shaking 的本意,本文所说的前 ...
- 消息队列那么多,为什么建议深入了解下RabbitMQ?
你为啥要在项目中选择xxx消息中间件? 提起消息队列,也许你的脑海里会不自觉地蹦出好多概念:JMS.Kafka.RocketMQ.AMQP.RabbitMQ.ActiveMQ.Pulsar.Redis ...
- Spring Boot 2.x 快速入门(下)HelloWorld示例详解
上篇 Spring Boot 2.x 快速入门(上)HelloWorld示例 进行了Sprint Boot的快速入门,以实际的示例代码来练手,总比光看书要强很多嘛,最好的就是边看.边写.边记.边展示. ...
随机推荐
- 自己动手,丰衣足食。普通键盘实现键盘宏(Windows和Mac版)
很多高端机械键盘,支持宏定义,例如我们可以设置"D"键为"dota",这样当我们按一下宏开启键,再按一下"D"键,就等价于分别按了" ...
- 【socket】Socket的三个功能类TCPClient、TCPListener 和 UDPClient
Socket的三个功能类TCPClient.TCPListener 和 UDPClient (转) 应用程序可以通过 TCPClient.TCPListener 和 UDPClient 类使用传输控制 ...
- 2016 系统设计第一期 (档案一)MVC 和 Bootstrap 表单转换
bootstrap <form role="form"> <div class="form-group"> <label for= ...
- Entity Framework 学习笔记(一)安装
1.通过 VS2013 下载,这个没有限制,因为我用的vs是2013 Entity Framework包
- 【bzoj3110】[Zjoi2013]K大数查询
Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置 ...
- 带括号的四则混合运算的算符优先算法-----java实现
1:主方法 package com.baidu; import java.text.NumberFormat;import java.util.ArrayList;import java.util.S ...
- MVC4中Ajax.BeginForm OnSuccess 不执行以及控制器返回JsonResult 提示下载的原因
这几天学习MVC的过程中,在学习Ajax.BeginForm时,一直遇到2个问题: 一. Ajax.BeginForm OnSuccess事件不执行 二.提交表单后,浏览器不识别json字符串,提示下 ...
- firefly笔记一之http模块
原地址:http://www.9miao.com/question-15-54380.html Firefly是免费开源的游戏服务器端框架,开发语言是python,基于twisted框架开发,作为一名 ...
- Java将整个文件夹里的文本中的字符串替换成另外一个字符串(可用于项目复制,变成另一个项目)
import org.junit.Test; import java.io.*; /** * User: HYY * Date: 13-8-18 * Time: 下午8:11 * To change ...
- 如何用Java语言向串口读写数据
原作者:赛迪网作者 shihuchen ,我在他的基础上进行了部分修改 [赛迪网讯]串口, RS-232-C(又称EIA RS-232-C,以下简称RS232)是在1970年由美国电子工业协会(EIA ...