RabbitMQ安装和使用(三)

之前的博客我们实现了RabbitMQ在Windows系统下的安装和使用,并且通过对队列的使用实现了简单的发送和接收功能。本部分主要介绍RabbitMQ的发布/订阅以及路由设置,主要实现以下功能。

实现步骤:

一:发布/订阅模式理论知识

1、转发器(Exchanges)

RabbitMQ消息模型的核心理念是生产者永远不会直接发送任何消息给队列,一般的情况生产者甚至不知道消息应该发送到哪些队列。相反的,生产者只能发送消息给转发器(Exchange)。转发器是非常简单的,一边接收从生产者发来的消息,另一边把消息推送到队列中。转发器必须清楚的知道消息如何处理它收到的每一条消息。是追加到一个指定的队列、追加到指定队列、或者扔掉,这些规则通过转发器的类型进行定义。

常用转发器及解释:

fanout:生产者发送到exchange的消息会被所有的消费者接受处理。

direct:生产者在发送消息至转换器时,会指定一个路由key,消费者消费的时候也会指定一个路由key,这样你发送的消息指定的是什么routingKey,那么转发器就会把消息转给相应队列对应的消费者进行处理。

topic:比direct类型更加灵活,提供.与*的匹配模式,让路由的绑定key与消费者的选择key更加强大。其中,.号可以匹配一个标识符,*号可以配置0个或多个标识符。

2、匿名转发器(nameless exchange)

前面说到生产者只能发送消息给转发器(Exchange),但是我们前两篇博客中的例子并没有使用到转发器,我们仍然可以发送和接收消息。这是因为我们使用了一个默认的转发器,它的标识符为””。之前发送消息的代码:

channel.BasicPublish("",QUEUE_NAME,MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());

第一个参数为转发器的名称,我们设置为””:如果存在routingKey(第二个参数),消息由routingKey决定发送到哪个队列。

现在我们可以指定消息发送到的转发器:

channel.BasicPublish( Exchange_Name,"", null, message.getBytes());

3、临时队列(Temporary queues)

前面的博客中我们都为队列指定了一个特定的名称。能够为队列命名对我们来说是很关键的,我们需要指定消费者为某个队列。当我们希望在生产者和消费者间共享队列时,为队列命名是很重要的。不过,对于我们很多系统中并不关心队列的名称。我们想要接收到所有的消息,而且我们也只对当前正在传递的数据的感兴趣。为了满足我们的需求,需要做两件事:
第一,无论什么时间连接到RabbitMQ我们都需要一个新的空的队列。我们可以随机创建队列,或者让服务器给我们提供一个随机队列的名称。
第二,一旦消费者与Rabbit断开,消费者所接收的那个队列应该被自动删除。
.Net中我们可以使用QueueDeclare()方法,不传递任何参数,来创建一个非持久的、唯一的、自动删除的队列且队列名称由服务器随机产生。
string queue_Name = channel.QueueDeclare().QueueName;

4、绑定(Bindings)

我们已经创建了一个转发器和队列,我们现在需要通过binding告诉转发器把消息发送给我们的队列。
channel.QueueBind(Queue_Name,Exchange_Name,””)参数1:队列名称 ;参数2:转发器名称。

二:源码实现

1、fanout类型

 Producer源码:

static void Main(string[] args)
        {
            //创建目标,并将目标地址、用户名、密码记录
            var factory = new ConnectionFactory();
            factory.HostName = "xxx.xxx.xxx.xxx";
            factory.UserName = "xxx";
            factory.Password = "xxx";
            //建立实例连接
            var connection = factory.CreateConnection();
            //建立连接RabbitMQ通道
            var channel = connection.CreateModel();
            //声明一个fanout类型的转发器Exchange_send
            channel.ExchangeDeclare("Exchange_send","fanout");
            //声明要发送的数据
            byte[] body = Encoding.UTF8.GetBytes("It's a fanout type!");
            channel.BasicPublish("Exchange_send", "",null,body);
            Console.WriteLine(DateTime.Now.ToString()+":Fanout type send success");
            Console.ReadKey();
        }

Consumer源码:

static void Main(string[] args)
        {
            //创建目标,并将目标地址、用户名、密码记录
            var factory = new ConnectionFactory();
	    factory.HostName = "xxx.xxx.xxx.xxx";
            factory.UserName = "xxx";
            factory.Password = "xxx";
            //建立实例连接 
            var connection = factory.CreateConnection(); 
            //建立连接RabbitMQ通道 
            var channel = connection.CreateModel(); 
            //声明一个fanout类型的转发器Exchange_send 
            channel.ExchangeDeclare("Exchange_send", "fanout"); 
            //创建一个非持久的、唯一的且自动删除的队列 
            string queue_Name = channel.QueueDeclare().QueueName; 
            //将队列绑定到转发器 
            channel.QueueBind(queue_Name, "Exchange_send", ""); 
            //用于接收消息 
            QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel); 
            //指定接收者,第二个参数false表示需要回执给rabbitmq,否则rabbitmq一直保存 
            channel.BasicConsume(queue_Name, false, consumer); 
            while(true) 
            { 
                 //接收消息并处理 
                 var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                 var body = ea.Body; 
                 var message = Encoding.UTF8.GetString(body); 
                 Console.WriteLine(DateTime.Now.ToString() + ":Received {0}", message); 
                 //消息处理完成后告诉客户端我已收到消息 
                 var body1 = Encoding.UTF8.GetBytes("I have received the message"); 
                 channel.BasicPublish("", "receive", null, body1); 
                 Console.WriteLine(DateTime.Now.ToString() + " send:{0}", "I have received the message"); 
                 //处理完了回执给rabbitmq,如果没有这行代码,RabbitMQ会一直存储这条消息 
                 channel.BasicAck(ea.DeliveryTag, true); 
            } 
            Console.ReadKey();
        }
2、direct类型

Producer源码:

private static String EXCHANGE_NAME = "Exchange_direct";
        private static String[] LOGTYPE = { "warning", "error" };
        static void Main(string[] args)
        {
            //创建目标,并将目标地址、用户名、密码记录
            var factory = new ConnectionFactory();
            factory.HostName = "xxx.xxx.xxx.xxx";
            factory.UserName = "xxx";
            factory.Password = "xxx";
            //建立实例连接 
            var connection = factory.CreateConnection(); 
            //建立连接RabbitMQ通道 
            var channel = connection.CreateModel(); 
            //声明一个direct类型的转发器 
            channel.ExchangeDeclare(EXCHANGE_NAME, "direct"); 
            // 发送5条消息 
            for (int i = 0; i < 5; i++) 
            { 
                 String message = ""; 
                 if (i / 2 == 0) 
                 { 
                      message = LOGTYPE[0] + "_log :it's warning " + i; 
                      // 发布消息至转发器,指定routingkey 
                      channel.BasicPublish(EXCHANGE_NAME, LOGTYPE[0], null, Encoding.UTF8.GetBytes(message)); 
                 } 
                 else 
                 { 
                      message = LOGTYPE[1] + "_log :it's error " + i; 
                      // 发布消息至转发器,指定routingkey 
                      channel.BasicPublish(EXCHANGE_NAME, LOGTYPE[1], null, Encoding.UTF8.GetBytes(message));
                 } 
                 Console.WriteLine("I have sent '" + message + "'"); 
            } 
            Console.ReadKey(); 
       }

Consumer01源码

        private static String EXCHANGE_NAME = "Exchange_direct";
        private static String[] LOGTYPE = { "warning", "error" };
        static void Main(string[] args)
        {
            //创建目标,并将目标地址、用户名、密码记录
            var factory = new ConnectionFactory();
            factory.HostName = "xxx.xxx.xxx.xxx";
            factory.UserName = "xxx";
            factory.Password = "xxx";
            //建立实例连接 
            var connection = factory.CreateConnection(); 
            //建立连接RabbitMQ通道 
            var channel = connection.CreateModel(); 
            //声明一个fanout类型的转发器Exchange_send 
            channel.ExchangeDeclare(EXCHANGE_NAME, "direct"); 
            //创建一个非持久的、唯一的且自动删除的队列 
            string queue_Name = channel.QueueDeclare().QueueName; 
            //将队列绑定到转发器 
            channel.QueueBind(queue_Name, EXCHANGE_NAME, LOGTYPE[0]); 
            //用于接收消息 
            QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel); 
            //指定接收者,第二个参数false表示需要回执给rabbitmq,否则rabbitmq一直保存 
            channel.BasicConsume(queue_Name, false, consumer); 
            while(true) 
            { 
                 //接收消息并处理 
                 var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue(); 
                 var body = ea.Body; var message = Encoding.UTF8.GetString(body); 
                 Console.WriteLine(DateTime.Now.ToString() + ":Received {0}", message); 
                 //消息处理完成后告诉客户端我已收到消息 
                 var body1 = Encoding.UTF8.GetBytes("I have received the message"); 
                 channel.BasicPublish("", "receive", null, body1);
                 Console.WriteLine(DateTime.Now.ToString() + " send:{0}", "I have received the message"); 
                 //处理完了回执给rabbitmq,如果没有这行代码,RabbitMQ会一直存储这条消息 
                 channel.BasicAck(ea.DeliveryTag, true); 
            } 
            Console.ReadKey(); 
       }
Consumer02源码:

        private static String EXCHANGE_NAME = "Exchange_direct";
        private static String[] LOGTYPE = { "warning", "error" };
        static void Main(string[] args)
        {
            //创建目标,并将目标地址、用户名、密码记录
            var factory = new ConnectionFactory();
            factory.HostName = "xxx.xxx.xxx.xxx";
            factory.UserName = "xxx";
            factory.Password = "xxx";
            //建立实例连接 
            var connection = factory.CreateConnection(); 
            //建立连接RabbitMQ通道 
            var channel = connection.CreateModel(); 
            //声明一个fanout类型的转发器Exchange_send 
            channel.ExchangeDeclare(EXCHANGE_NAME, "direct"); 
            //创建一个非持久的、唯一的且自动删除的队列 
            string queue_Name = channel.QueueDeclare().QueueName; 
            //将队列绑定到转发器 
            channel.QueueBind(queue_Name, EXCHANGE_NAME, LOGTYPE[1]); 
            //用于接收消息 
            QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel); 
            //指定接收者,第二个参数false表示需要回执给rabbitmq,否则rabbitmq一直保存 
            channel.BasicConsume(queue_Name, false, consumer); 
            while(true) 
            { 
                 //接收消息并处理 
                 var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue(); 
                 var body = ea.Body; var message = Encoding.UTF8.GetString(body); 
                 Console.WriteLine(DateTime.Now.ToString() + ":Received {0}", message); 
                 //消息处理完成后告诉客户端我已收到消息 
                 var body1 = Encoding.UTF8.GetBytes("I have received the message"); 
                 channel.BasicPublish("", "receive", null, body1);
                 Console.WriteLine(DateTime.Now.ToString() + " send:{0}", "I have received the message"); 
                 //处理完了回执给rabbitmq,如果没有这行代码,RabbitMQ会一直存储这条消息 
                 channel.BasicAck(ea.DeliveryTag, true); 
            } 
            Console.ReadKey(); 
       }
3、topic类型

Producer源码:

private static String EXCHANGE_NAME = "Exchange_topic";
        static void Main(string[] args)
        {
            //创建目标,并将目标地址、用户名、密码记录
            var factory = new ConnectionFactory();
            factory.HostName = "xxx.xxx.xxx.xxx";
            factory.UserName = "xxx";
            factory.Password = "xxx";
            //建立实例连接
            var connection = factory.CreateConnection();
            //建立连接RabbitMQ通道
            var channel = connection.CreateModel();
            //声明一个direct类型的转发器
            channel.ExchangeDeclare(EXCHANGE_NAME, "topic");
            String[] LOGTYPE = new String[] { "kernal.info", "cron.warning", "auth.info", "kernel.critical" };
            // 发送5条消息
            for (int i = 0; i < 4; i++)
            {
                string message = LOGTYPE[i] + ":it's " + i;
                // 发布消息至转发器,指定routingkey
                channel.BasicPublish(EXCHANGE_NAME, LOGTYPE[i], null, Encoding.UTF8.GetBytes(message));
                Console.WriteLine("I have sent '" + message + "'");
            }
            Console.ReadKey();
        }

Consumer源码:

private static String EXCHANGE_NAME = "Exchange_topic";
        static void Main(string[] args)
        {
            //创建目标,并将目标地址、用户名、密码记录
            var factory = new ConnectionFactory();
            factory.HostName = "xxx.xxx.xxx.xxx";
            factory.UserName = "xxx";
            factory.Password = "xxx";
            //建立实例连接
            var connection = factory.CreateConnection();
            //建立连接RabbitMQ通道
            var channel = connection.CreateModel();
            //声明一个fanout类型的转发器Exchange_send
            channel.ExchangeDeclare(EXCHANGE_NAME, "topic");
            //创建一个非持久的、唯一的且自动删除的队列
            string queue_Name = channel.QueueDeclare().QueueName;
            //将队列绑定到转发器
            channel.QueueBind(queue_Name, EXCHANGE_NAME, "cron.*");
            //用于接收消息
            QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
            //指定接收者,第二个参数false表示需要回执给rabbitmq,否则rabbitmq一直保存
            channel.BasicConsume(queue_Name, false, consumer);
            while(true)
            {
                //接收消息并处理
                var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                var body = ea.Body;
                var message = Encoding.UTF8.GetString(body);
                Console.WriteLine(DateTime.Now.ToString() + ":Received {0}", message);
                //消息处理完成后告诉客户端我已收到消息
                var body1 = Encoding.UTF8.GetBytes("I have received the message");
                channel.BasicPublish("", "receive", null, body1);
                Console.WriteLine(DateTime.Now.ToString() + " send:{0}", "I have received the message");
                //处理完了回执给rabbitmq,如果没有这行代码,RabbitMQ会一直存储这条消息
                channel.BasicAck(ea.DeliveryTag, true);
            }
            Console.ReadKey();
        }

不同Consumer接收不同消息,只需要改QueueBind的第三个参数即可。











                
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值