• NetCore RabbitMQ 发布订阅模式,消息广播


    十年河东,十年河西,莫欺少年穷

    学无止境,精益求精

    上篇博客介绍了RabbitMQ的六种工作模式 RabbitMQ的六种工作模式 仅登录用户可见

    RabbitMQ的简单模式和Work工作模式请参考:NetCore RabbitMQ 简介及兔子生产者、消费者 【简单模式,work工作模式,竞争消费】

    本篇博客使用NetCore完成RabbitMQ发布订阅模式中的广播模式

    何为广播模式?

     publish/subscribe发布订阅(共享资源)

    在这里插入图片描述

    1. X代表交换机rabbitMQ内部组件,erlang 消息产生者是代码完成,代码的执行效率不高,消息产生者将消息放入交换机,交换机发布订阅把消息发送到所有消息队列中,对应消息队列的消费者拿到消息进行消费
    2. 相关场景:邮件群发,群聊天,广播(广告)

    上图中X代表交换机,RabbitMQ中交换机的类型分为四种,分别为广播模式,定向模式,通配符模式,参数匹配模式

    ExchangeType.Fanout【广播模式】 

    ExchangeType.Direct【定向模式】 

    ExchangeType.Topic【通配符模式】 

    ExchangeType.Headers 【参数匹配模式】

    广播模式生产者

    广播模式创建生产者,分为如下步骤,

    1、声明一个交换机

    2、声明广播的队列

    3、交换机和队列进行绑定

    4、生产消息

    以上步骤用NetCore 实现如下:

    using RabbitMQ.Client;
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    
    namespace RabbitMqProducer
    {
        class Program
        {
            static void Main(string[] args)
            {
                ConnectionFactory factory = new ConnectionFactory();
                factory.HostName = "127.0.0.1"; //主机名
                factory.UserName = "guest";//使用的用户
                factory.Password = "guest";//用户密码
                factory.Port = 5672;//端口号
                factory.VirtualHost = "/"; //虚拟主机
                factory.MaxMessageSize = 1024; //消息最大字节数
                using (var connection = factory.CreateConnection()) 
                {
                    //rabbitMQ 基于信道进行通信,因此,我们需要实例化信道Channel
                    using (var channel = connection.CreateModel())
                    {
                        //exchange 交换机名称
                        //type  交换机类型  ExchangeType.Direct【定向模式】  ExchangeType.Fanout【广播模式】  ExchangeType.Topic【通配符模式】  ExchangeType.Headers 【参数匹配模式】
                        //durable 是否持久化
                        //autoDelete 队列是否为临时队列
                        //arguments  其他配置 详见博客:https://www.cnblogs.com/chenwolong/p/RabbitMQ_S.html
                        //void ExchangeDeclare(string exchange, string type, bool durable, bool autoDelete, IDictionary<string, object> arguments);
                        //声明一个交换机
                        string Ename = "ExRabbitMQ";
                        channel.ExchangeDeclare(Ename, ExchangeType.Fanout, false, false, null);
                        //声明广播的队列
                        string Qname_1 = "RabbitMQ_Queue_1";
                        string Qname_2 = "RabbitMQ_Queue_2";
                        channel.QueueDeclare(Qname_1, false, false, false, null);
                        channel.QueueDeclare(Qname_2, false, false, false, null);
                        //交换机 队列 绑定
                        //queue 队列名称
                        //exchange  交换机名称
                        //routingKey  路由规则  
                        //void QueueBind(string queue, string exchange, string routingKey, IDictionary<string, object> arguments);
                        string routingKey = "EQ"; //路由匹配规则 交换机通过routingKey广播消息到绑定的队列
                        channel.QueueBind(Qname_1, Ename, routingKey);
                        channel.QueueBind(Qname_2, Ename, routingKey);
                        //发送消息
                        for(int i = 0; i < 100; i++)
                        {
                            var messages = "I am RabbitMQ"; //传递的消息内容
                                                            //exchange 交换机,如果使用默认的交换机,那么routingKey要和队列的名称一致
                                                            //routingKey:路由  
                                                            //basicProperties : 用于基础属性设置
                            ///BasicPublish(this IModel model, string exchange, string routingKey, IBasicProperties basicProperties, ReadOnlyMemory<byte> body);
                            channel.BasicPublish(Ename, routingKey, null, Encoding.UTF8.GetBytes(messages+"_"+i)); //生产消息
                        }
                    }
                }
                Console.Read();
            }
        }
    }

    这里需要说明的是,当发布订阅模式为广播时,需要定义路由规则routingKey,绑定时,routingKey必须保持一致,RabbitMQ广播是通过routingKey进行队列匹配的。

    消费者

    广播模式生产者代码中,我们创建了两个队列,因此,我们需要两个消费者分别消费不同队列的消息,如下:

    消费者1

    using RabbitMQ.Client;
    using RabbitMQ.Client.Events;
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    
    namespace RabbitMqConsumer
    {
        class Program
        {
            static void Main(string[] args)
            {
                ConnectionFactory factory = new ConnectionFactory();
                factory.HostName = "127.0.0.1"; //主机名
                factory.UserName = "guest";//使用的用户
                factory.Password = "guest";//用户密码
                factory.Port = 5672;//端口号
                factory.VirtualHost = "/"; //虚拟主机
                factory.MaxMessageSize = 1024; //消息最大字节数
                                               //创建连接
                var connection = factory.CreateConnection();
                //创建通道
                var channel = connection.CreateModel();
    
                //事件基本消费者
                EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
    
                //接收到消息事件
                consumer.Received += (ch, ea) =>
                {
                    var message = Encoding.UTF8.GetString(ea.Body.ToArray());
                    Console.WriteLine($"RabbitMQConsumer_1 收到消息: {message}");
                    //确认该消息已被消费
                    channel.BasicAck(ea.DeliveryTag, false); Thread.Sleep(100);
                };
                //启动消费者 
                string Qname = "RabbitMQ_Queue_1";
                channel.BasicConsume(Qname, false, consumer);
                Console.WriteLine("消费者已启动");
                Console.ReadKey();
                channel.Dispose();
                connection.Close();
            }
    
             
    
        }
    }

    消费者2

    using RabbitMQ.Client;
    using RabbitMQ.Client.Events;
    using System;
    using System.Text;
    using System.Threading;
    
    namespace RabbitMQConsumer_2
    {
        class Program
        {
            static void Main(string[] args)
            {
                ConnectionFactory factory = new ConnectionFactory();
                factory.HostName = "127.0.0.1"; //主机名
                factory.UserName = "guest";//使用的用户
                factory.Password = "guest";//用户密码
                factory.Port = 5672;//端口号
                factory.VirtualHost = "/"; //虚拟主机
                factory.MaxMessageSize = 1024; //消息最大字节数
                                               //创建连接
                var connection = factory.CreateConnection();
                //创建通道
                var channel = connection.CreateModel();
    
                //事件基本消费者
                EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
    
                //接收到消息事件
                consumer.Received += (ch, ea) =>
                {
                    var message = Encoding.UTF8.GetString(ea.Body.ToArray());
                    Console.WriteLine($"RabbitMQConsumer_2 收到消息: {message}");
                    //确认该消息已被消费
                    channel.BasicAck(ea.DeliveryTag, false);
                    Thread.Sleep(100);
                };
                //启动消费者 
    
                string Qname = "RabbitMQ_Queue_2";
                channel.BasicConsume(Qname, false, consumer);
                Console.WriteLine("消费者已启动");
                Console.ReadKey();
                channel.Dispose();
                connection.Close();
            }
        }
    }

    效果如下:

     @陈卧龙的伯乐

  • 相关阅读:
    解决在PDF文档中复制代码报错问题
    JAVA高级复习泛型
    SpringBoot高级监听原理
    SpringBoot整合其它框架整合Junit
    SpringBoot高级监控
    JAVA基础复习异常处理
    SpringBoot 整合 webservice 示例
    关于ScrollView的子View无法布满屏幕的问题
    Android开发中头疼的R文件问题
    博客园美化[SimpleMemory主题+tctip插件]
  • 原文地址:https://www.cnblogs.com/chenwolong/p/RabbitMQ_Fanout.html
Copyright © 2020-2023  润新知