Net中使用 RabbitMq | Fanout ExChange 广播模式(分发模式)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Fanbin168/article/details/89332376

Fanout ExChange属于广播模式(分发模式),因为这种模式不走路由,所以它的性能是最高的

RabbitMQ中的Exchange有四种类型,不同的类型有着不同的路由策略,RabbitMQ常用的Exchange Type有fanout、direct、topic、headers这四种。

Exchange是按照什么逻辑将消息路由到Queue的?RabbitMQ中通过Binding将Exchange与Queue关联起来,这样RabbitMQ就知道如何正确地将消息路由到指定的Queue了。在direct模式下,RabbitMQ中通过Binding将Exchange与Queue关联起来,这个绑定的过程中会指定RoutingKey,而fanout模式下,则不用指定RoutingKey

  1. direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。
  2. topic类型中所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息
  3. fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。
  4. headers类型的Exchange不依赖于routing key与binding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。

我们看到生产者将消息投递到Queue中,实际上这在RabbitMQ中这种事情永远都不会发生。实际的情况是,生产者将消息发送到Exchange(交换器),由Exchange将消息路由到一个或多个Queue中(或者丢弃)。

 广播模式是实时的,也就是说,在生产端产生消息的时候,消费端必须是处于监听状态的(这就要求必须先启动消费者端),才能从队列中获取消息,否则就收不到本次消息,哪怕再次启动。就像广播电台和收音机一样,广播电台的内容一直播放,如果收音机不打开就收听不到,即使后面打开了,先前的内容也播放完了。

Fanout模式下 必须先启动消费者端,然后再生产者端。

ProducterApp:生产者端

using RabbitMQ.Client;
using System.Text;

namespace ProducterApp
{
    class Program
    {
        /// 连接配置
        /// </summary>
        private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory() //创建一个工厂连接对象
        {
            HostName = "192.168.31.30",
            UserName = "admin",
            Password = "admin",
            VirtualHost = "/vhost001", //如果不设置,虚拟主机名称路径默认为 /
            Port = 5672, //注意:5672 --是client端通信口   15672 -- 是管理界面ui端口           
        };
        /// <summary>
        /// 路由名称
        /// </summary>
        const string ExchangeName = "exchange119";
        static void Main(string[] args)
        {
            using (IConnection conn = rabbitMqFactory.CreateConnection()) //创建一个连接
            {

                using (IModel channel = conn.CreateModel()) //创建一个Channel
                {
                    //注意:在Topic模型下,生产者段不需要创建Queue 自然也不需要设定Queue与Exchange绑定

                    //Exchange的Type类型有:direct,topic, fanout,headers
                    //direct:所有发送到Direct Exchange的消息都会被转发到RouteKey中指定的Queue;当消费者要消费这个Queue中的消息都会时候它要求消费者的RoutingKey与生产者的RoutingKey完全匹配
                    //topic:所有发送到Topic Exchange的消息都会转发到所有关心的RoutingKey

                    //durable是Exchange(交换机)的属性,它表示是否需要持久化,为true则为持久化。false表示不需要持久化

                    //autoDelete:它是Exchange(交换机)的属性,它的值有true和false两种
                    //为true 则表示当最后一个绑定到Exchange(交换机)上的Queue(队列)删除后,就自动删除该Exchange
                    //这段话也很好理解,假如Exchange(交换机)上绑定了三个Queue(队列),当这个三个Queue(队列)都被删除的时候这个Exchange(交换机)将会被自动删除

                    //arguments:它是扩展参数,用于扩展AMQP协议自制定化的使用
                    channel.ExchangeDeclare(ExchangeName, "fanout", durable: false, autoDelete: false, arguments: null); //声明一个Exchange(交换机)

                    var props = channel.CreateBasicProperties();
                    props.Persistent = true;

                    for (int i = 0; i < 5; i++)
                    {
                        //发送的消息必须是二进制的
                        var msg = Encoding.UTF8.GetBytes("你好中国,这是我的第" + i + "条消息");
                        channel.BasicPublish(exchange: ExchangeName, routingKey: "", basicProperties: props, body: msg);                       
                    }
                }
            }
        }
    }
}

CustomerApp:消费者端

using RabbitMQ.Client;
using System;
using System.Text;

namespace CustomerApp
{
    class Program
    {
        /// <summary>
        /// 连接配置
        /// </summary>
        private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory()
        {
            HostName = "192.168.31.30",
            UserName = "admin",
            Password = "admin",
            Port = 5672,
            VirtualHost = "/vhost001",
        };
        /// <summary>
        /// 路由名称
        /// </summary>
        const string ExchangeName = "exchange119";
        //队列名称
        const string QueueName = "queue119";
        static void Main(string[] args)
        {
            using (IConnection conn = rabbitMqFactory.CreateConnection())
            {
                using (IModel channel = conn.CreateModel())
                {
                    //创建交换机这里将Exchange(交换机)Type设定为fanout 【消费者端的交换机名称要与生产者端的交换机名称保持一致】
                    channel.ExchangeDeclare(ExchangeName, "fanout", durable: false, autoDelete: false, arguments: null);
                    //创建队列【消费者端需要创建队列,生产者端不需要创建队列】
                    channel.QueueDeclare(QueueName, durable: false, autoDelete: false, exclusive: false, arguments: null);

                    channel.QueueBind(QueueName, ExchangeName, routingKey: ""); //fanout模式下Exchange与Queue绑定不需要指定RoutingKey,所以这里设为空字符串就行
                    while (true)
                    {
                        //System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
                        BasicGetResult msgResponse = channel.BasicGet(QueueName, autoAck: true);//这个true表示消费完这条数据是否删除,true表示删除,false表示不删除
                        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));
                        }                      
                    }
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Fanbin168/article/details/89332376