【开发笔记系列(四)】MQ消息队列,发布与订阅

VS,项目框架.NET Core 3.1

导入Nuget包,RabbitMQ.client

下面讲解下Fanout、Direct、Topic的区别

Fanout

fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。

Direct

direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。

Topic

前面讲到direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但这里的匹配规则有些不同,它约定:

  • routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
  • binding key与routing key一样也是句点号“. ”分隔的字符串
  • binding key中可以存在两种特殊字符“”与“#”,用于做模糊匹配,其中“”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)

MQ工具类:

    public class RabbitMq
    {
        private static IConfiguration Configuration;
        private readonly ConnectionFactory _factory;


        public static void Configure(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public RabbitMq()
        {
            _factory = new ConnectionFactory() { HostName = Configuration.GetSection("RabbitMqSetting:HostName").Value, UserName = Configuration.GetSection("RabbitMqSetting:UserName").Value, Password = Configuration.GetSection("RabbitMqSetting:Password").Value, VirtualHost = Configuration.GetSection("RabbitMqSetting:VirtualHost").Value, Port = int.Parse(Configuration.GetSection("RabbitMqSetting:Port").Value) };
        }

        public bool QueueBind(string queuename, string exchange, string routekey)
        {
            using (var connection = _factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.QueueDeclare(queue: queuename,
                                         durable: true,
                                         exclusive: false,
                                         autoDelete: false,
                                         arguments: null);
                    channel.QueueBind(queuename, exchange, routekey);
                    Console.WriteLine($"{queuename} declared. ");
                    return true;
                }
            }
        }

        public bool ExchangeSendTopic(string exchange, string routingKey, string msg)
        {
            using (var connection = _factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.ExchangeDeclare(exchange, ExchangeType.Topic, true, false);

                    string message = $"{msg}";
                    var body = Encoding.UTF8.GetBytes(message);

                    channel.BasicPublish(exchange: exchange,
                                         routingKey: routingKey,
                                         basicProperties: null,
                                         body: body);

                    Console.WriteLine($"Sent {exchange} {msg}");
                    return true;
                }
            }
        }


        public bool ExchangeSendFanout(string exchange, string routingKey, string msg)
        {
            using (var connection = _factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.ExchangeDeclare(exchange, ExchangeType.Fanout, true, false);

                    string message = $"{msg}";
                    var body = Encoding.UTF8.GetBytes(message);

                    channel.BasicPublish(exchange: exchange,
                                         routingKey: routingKey,
                                         basicProperties: null,
                                         body: body);

                    Console.WriteLine($"Sent {exchange} {msg}");
                    return true;
                }
            }
        }

        public void QueueReceive(string queuename)
        {
            var connection = _factory.CreateConnection();

            var channel = connection.CreateModel();

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body.ToArray();
                var message = System.Text.Encoding.UTF8.GetString(body);
                Console.WriteLine(" [x] Received {0}", message);
            };
            channel.BasicConsume(queue: queuename,
                                 autoAck: true,
                                 consumer: consumer);
        }
    }

appsettings配置文件中:

 "RabbitMqSetting": {
    "HostName": "192.168.xx.xxx",
    "UserName": "name",
    "Password": "pass123",
    "Port": "56720",
    "VirtualHost": "System"
  },

创建临时队列

String queueName = mq.QueueReceive(system);

MQ后端管理页面先创建一个虚拟机。

在创建完虚拟机后,在代码接口端调用MQ,会自动生成该代码中设置的交换机和消息队列

空字符串表示默认或无名称交换机:消息能路由发送到队列中其实 是由 routingKey(bindingkey)绑定 key 指定的,如果它存在的话。 那么这种情况下,MQ会走默认的交换机(AMQP default)

生产者、消费者这个关键key(Routing key)


以上是创建虚拟机、发布信息队列

接下来是订阅、消费信息

//调用绑定
Mq.QueueBind(QueueName, ExchangeName, RoutingKey);

  public bool QueueBind(string queuename, string exchange, string routekey)
        {
            using (var connection = _factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    string name=channel.QueueDeclare().QueueName.Split(".")[1];//获取随机队列
                    channel.QueueDeclare(queue: name,
                                         durable: true,
                                         exclusive: false,
                                         autoDelete: false,
                                         arguments: null);
                    channel.QueueBind(name, exchange, routekey);
                    Console.WriteLine($"{name} declared. ");

                    QueueReceive(name);
                    return true;
                }
            }
        }


  public void QueueReceive(string queuename)
        {
            var connection = _factory.CreateConnection();

            var channel = connection.CreateModel();

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body.ToArray();
                var message = System.Text.Encoding.UTF8.GetString(body);
                Console.WriteLine(" [x] Received {0}", message);
            };
            channel.BasicConsume(queue: queuename,
                                 autoAck: true,
                                 consumer: consumer);
        }

此时定义好订阅通道,生产者消费者都会通过指定交换机中的队列获取推送信息

控制台输出:

posted @ 2022-05-06 15:53  Yan-X  阅读(488)  评论(0)    收藏  举报