上一篇文章中,介绍了在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实践[示例篇]的更多相关文章

  1. NET下RabbitMQ实践[配置篇]

    这个系列目前计划写四篇,分别是配置,示例,WCF发布,实战.当然不排除加餐情况.  介绍: rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统.他遵循Mozilla Publi ...

  2. NET下RabbitMQ实践[实战篇]

    之前的文章中,介绍了如何将RabbitMQ以WCF方式进行发布.今天就介绍一下我们产品中如何使用RabbitMQ的!          在Discuz!NT企业版中,提供了对HTTP错误日志的记录功能 ...

  3. NET下RabbitMQ实践[WCF发布篇]

    在之前的两篇文章中,主要介绍了RabbitMQ环境配置,简单示例的编写.今天将会介绍如何使用WCF将RabbitMQ列队以服务的方式进行发布.          注:因为RabbitMQ的官方.net ...

  4. 实践详细篇-Windows下使用VS2015编译的Caffe训练mnist数据集

    上一篇记录的是学习caffe前的环境准备以及如何创建好自己需要的caffe版本.这一篇记录的是如何使用编译好的caffe做训练mnist数据集,步骤编号延用上一篇 <实践详细篇-Windows下 ...

  5. 实践详细篇-Windows下使用Caffe训练自己的Caffemodel数据集并进行图像分类

    三:使用Caffe训练Caffemodel并进行图像分类 上一篇记录的是如何使用别人训练好的MNIST数据做训练测试.上手操作一边后大致了解了配置文件属性.这一篇记录如何使用自己准备的图片素材做图像分 ...

  6. Python操作rabbitmq 实践笔记

    发布/订阅  系统 1.基本用法 生产者 import pika import sys username = 'wt' #指定远程rabbitmq的用户名密码 pwd = ' user_pwd = p ...

  7. Tree-Shaking性能优化实践 - 原理篇

    Tree-Shaking性能优化实践 - 原理篇   一. 什么是Tree-shaking 先来看一下Tree-shaking原始的本意 上图形象的解释了Tree-shaking 的本意,本文所说的前 ...

  8. 消息队列那么多,为什么建议深入了解下RabbitMQ?

    你为啥要在项目中选择xxx消息中间件? 提起消息队列,也许你的脑海里会不自觉地蹦出好多概念:JMS.Kafka.RocketMQ.AMQP.RabbitMQ.ActiveMQ.Pulsar.Redis ...

  9. Spring Boot 2.x 快速入门(下)HelloWorld示例详解

    上篇 Spring Boot 2.x 快速入门(上)HelloWorld示例 进行了Sprint Boot的快速入门,以实际的示例代码来练手,总比光看书要强很多嘛,最好的就是边看.边写.边记.边展示. ...

随机推荐

  1. Linux安装oracle 10g常见问题之——ORA-01078,LRM-00109,ORA-01102

    [oracle@toughhou database]$ sqlplus /nolog SQL> conn / as sysdba SQL> startup ORA-01078: failu ...

  2. java多态与异常处理——动手动脑

    编写一个程序,此程序在运行时要求用户输入一个 整数,代表某门课的考试成绩,程序接着给出“不及格”.“及格”.“中”.“良”.“优”的结论. 要求程序必须具备足够的健壮性,不管用户输入什 么样的内容,都 ...

  3. 使用Yeoman搭建 AngularJS 应用 (7) —— 让我们搭建一个网页应用

    原文地址:http://yeoman.io/codelab/preview-inbrowser.html 开启你的服务 运行Grunt任务,通过输入下面的命令来创建一个本地Node的http服务,地址 ...

  4. Apache2.2+php5.4在windows上配置实例

    这几天一直在win8.1上配置apache+php环境,网上看了很多文章,自己又犯了很多错误才配置成功,对新手来说真是有点小难. 自己打算把配置的详细过程写下来,好帮助其他新手快速配置. 在这里参考了 ...

  5. @Autowired获取配置文件中被注入实例的两种方式

    一.说明 二.那么在JavaBean中如何通过@Autowired获取该实例呢?有两种方式: 1.直接获取 @RunWith(SpringJUnit4ClassRunner.class) @Conte ...

  6. Binary search for the first element greater than target

    We all know how to search through an array for an element whose value equals the target value, but h ...

  7. 团体程序设计天梯赛-练习集L1-022. 奇偶分家

    L1-022. 奇偶分家 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 给定N个正整数,请统计奇数和偶数各有多少个? 输入格式 ...

  8. Unity3D 自动打包整个项目(以AssetBundle实现)

    原地址:http://blog.csdn.net/huang7jiao/article/details/18370653 需求: 在移动开发中,手动控制资源的加载.释放和热更新,是很有必要的. 而Un ...

  9. solr教程,值得刚接触搜索开发人员一看

    http://blog.csdn.net/awj3584/article/details/16963525 Solr调研总结 开发类型 全文检索相关开发 Solr版本 4.2 文件内容 本文介绍sol ...

  10. IsBadStringPtr、IsBadWritePtr

    判断调用进程是否拥有对指定字符串指针的读取权限,函数原型如下: BOOL IsBadStringPtr( LPCTSTR lpsz, UINT_PTR ucchMax); 参数: lpsz: 输入参数 ...